Merge tag 'asoc-v4.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Updates for v4.1

More updates for v4.1, pretty much all drivers:

 - Lots of cleanups from Lars, mainly moving things from the CODEC level
   to the card level.
 - Continuing improvements to rcar from Morimoto-san, pcm512x from
   Howard and Peter, the Intel platforms from Vinod, Jie, Jin and Han,
   and to rt5670 from Bard.
 - Support for some non-DSP Qualcomm platforms, Google's Storm
   platform, Maxmim MAX98925 CODECs and the Ingenic JZ4780 SoC.
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index 42a0a39..e7193aa 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -466,7 +466,11 @@
 - add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
   I/O jack for allowing to change the headphone amp and mic bias VREF
   capabilities
-- power_down_unused (bool): power down the unused widgets
+- power_save_node (bool): advanced power management for each widget,
+  controlling the power sate (D0/D3) of each widget node depending on
+  the actual pin and stream states
+- power_down_unused (bool): power down the unused widgets, a subset of
+  power_save_node, and will be dropped in future
 - add_hp_mic (bool): add the headphone to capture source if possible
 - hp_mic_detect (bool): enable/disable the hp/mic shared input for a
   single built-in mic case; default true
diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt
new file mode 100644
index 0000000..0b191a2
--- /dev/null
+++ b/Documentation/sound/alsa/timestamping.txt
@@ -0,0 +1,200 @@
+The ALSA API can provide two different system timestamps:
+
+- Trigger_tstamp is the system time snapshot taken when the .trigger
+callback is invoked. This snapshot is taken by the ALSA core in the
+general case, but specific hardware may have synchronization
+capabilities or conversely may only be able to provide a correct
+estimate with a delay. In the latter two cases, the low-level driver
+is responsible for updating the trigger_tstamp at the most appropriate
+and precise moment. Applications should not rely solely on the first
+trigger_tstamp but update their internal calculations if the driver
+provides a refined estimate with a delay.
+
+- tstamp is the current system timestamp updated during the last
+event or application query.
+The difference (tstamp - trigger_tstamp) defines the elapsed time.
+
+The ALSA API provides reports two basic pieces of information, avail
+and delay, which combined with the trigger and current system
+timestamps allow for applications to keep track of the 'fullness' of
+the ring buffer and the amount of queued samples.
+
+The use of these different pointers and time information depends on
+the application needs:
+
+- 'avail' reports how much can be written in the ring buffer
+- 'delay' reports the time it will take to hear a new sample after all
+queued samples have been played out.
+
+When timestamps are enabled, the avail/delay information is reported
+along with a snapshot of system time. Applications can select from
+CLOCK_REALTIME (NTP corrections including going backwards),
+CLOCK_MONOTONIC (NTP corrections but never going backwards),
+CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode
+dynamically with sw_params
+
+
+The ALSA API also provide an audio_tstamp which reflects the passage
+of time as measured by different components of audio hardware.  In
+ascii-art, this could be represented as follows (for the playback
+case):
+
+
+--------------------------------------------------------------> time
+  ^               ^              ^                ^           ^
+  |               |              |                |           |
+ analog         link            dma              app       FullBuffer
+ time           time           time              time        time
+  |               |              |                |           |
+  |< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
+  |<----------------- delay---------------------->|           |
+			         |<----ring buffer length---->|
+
+The analog time is taken at the last stage of the playback, as close
+as possible to the actual transducer
+
+The link time is taken at the output of the SOC/chipset as the samples
+are pushed on a link. The link time can be directly measured if
+supported in hardware by sample counters or wallclocks (e.g. with
+HDAudio 24MHz or PTP clock for networked solutions) or indirectly
+estimated (e.g. with the frame counter in USB).
+
+The DMA time is measured using counters - typically the least reliable
+of all measurements due to the bursty natured of DMA transfers.
+
+The app time corresponds to the time tracked by an application after
+writing in the ring buffer.
+
+The application can query what the hardware supports, define which
+audio time it wants reported by selecting the relevant settings in
+audio_tstamp_config fields, get an estimate of the timestamp
+accuracy. It can also request the delay-to-analog be included in the
+measurement. Direct access to the link time is very interesting on
+platforms that provide an embedded DSP; measuring directly the link
+time with dedicated hardware, possibly synchronized with system time,
+removes the need to keep track of internal DSP processing times and
+latency.
+
+In case the application requests an audio tstamp that is not supported
+in hardware/low-level driver, the type is overridden as DEFAULT and the
+timestamp will report the DMA time based on the hw_pointer value.
+
+For backwards compatibility with previous implementations that did not
+provide timestamp selection, with a zero-valued COMPAT timestamp type
+the results will default to the HDAudio wall clock for playback
+streams and to the DMA time (hw_ptr) in all other cases.
+
+The audio timestamp accuracy can be returned to user-space, so that
+appropriate decisions are made:
+
+- for dma time (default), the granularity of the transfers can be
+  inferred from the steps between updates and in turn provide
+  information on how much the application pointer can be rewound
+  safely.
+
+- the link time can be used to track long-term drifts between audio
+  and system time using the (tstamp-trigger_tstamp)/audio_tstamp
+  ratio, the precision helps define how much smoothing/low-pass
+  filtering is required. The link time can be either reset on startup
+  or reported as is (the latter being useful to compare progress of
+  different streams - but may require the wallclock to be always
+  running and not wrap-around during idle periods). If supported in
+  hardware, the absolute link time could also be used to define a
+  precise start time (patches WIP)
+
+- including the delay in the audio timestamp may
+  counter-intuitively not increase the precision of timestamps, e.g. if a
+  codec includes variable-latency DSP processing or a chain of
+  hardware components the delay is typically not known with precision.
+
+The accuracy is reported in nanosecond units (using an unsigned 32-bit
+word), which gives a max precision of 4.29s, more than enough for
+audio applications...
+
+Due to the varied nature of timestamping needs, even for a single
+application, the audio_tstamp_config can be changed dynamically. In
+the STATUS ioctl, the parameters are read-only and do not allow for
+any application selection. To work around this limitation without
+impacting legacy applications, a new STATUS_EXT ioctl is introduced
+with read/write parameters. ALSA-lib will be modified to make use of
+STATUS_EXT and effectively deprecate STATUS.
+
+The ALSA API only allows for a single audio timestamp to be reported
+at a time. This is a conscious design decision, reading the audio
+timestamps from hardware registers or from IPC takes time, the more
+timestamps are read the more imprecise the combined measurements
+are. To avoid any interpretation issues, a single (system, audio)
+timestamp is reported. Applications that need different timestamps
+will be required to issue multiple queries and perform an
+interpolation of the results
+
+In some hardware-specific configuration, the system timestamp is
+latched by a low-level audio subsytem, and the information provided
+back to the driver. Due to potential delays in the communication with
+the hardware, there is a risk of misalignment with the avail and delay
+information. To make sure applications are not confused, a
+driver_timestamp field is added in the snd_pcm_status structure; this
+timestamp shows when the information is put together by the driver
+before returning from the STATUS and STATUS_EXT ioctl. in most cases
+this driver_timestamp will be identical to the regular system tstamp.
+
+Examples of typestamping with HDaudio:
+
+1. DMA timestamp, no compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=1
+playback: systime: 341121338 nsec, audio time 342000000 nsec, 	systime delta -878662
+playback: systime: 426236663 nsec, audio time 427187500 nsec, 	systime delta -950837
+playback: systime: 597080580 nsec, audio time 598000000 nsec, 	systime delta -919420
+playback: systime: 682059782 nsec, audio time 683020833 nsec, 	systime delta -961051
+playback: systime: 852896415 nsec, audio time 853854166 nsec, 	systime delta -957751
+playback: systime: 937903344 nsec, audio time 938854166 nsec, 	systime delta -950822
+
+2. DMA timestamp, compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=1 -d
+playback: systime: 341053347 nsec, audio time 341062500 nsec, 	systime delta -9153
+playback: systime: 426072447 nsec, audio time 426062500 nsec, 	systime delta 9947
+playback: systime: 596899518 nsec, audio time 596895833 nsec, 	systime delta 3685
+playback: systime: 681915317 nsec, audio time 681916666 nsec, 	systime delta -1349
+playback: systime: 852741306 nsec, audio time 852750000 nsec, 	systime delta -8694
+
+3. link timestamp, compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=2 -d
+playback: systime: 341060004 nsec, audio time 341062791 nsec, 	systime delta -2787
+playback: systime: 426242074 nsec, audio time 426244875 nsec, 	systime delta -2801
+playback: systime: 597080992 nsec, audio time 597084583 nsec, 	systime delta -3591
+playback: systime: 682084512 nsec, audio time 682088291 nsec, 	systime delta -3779
+playback: systime: 852936229 nsec, audio time 852940916 nsec, 	systime delta -4687
+playback: systime: 938107562 nsec, audio time 938112708 nsec, 	systime delta -5146
+
+Example 1 shows that the timestamp at the DMA level is close to 1ms
+ahead of the actual playback time (as a side time this sort of
+measurement can help define rewind safeguards). Compensating for the
+DMA-link delay in example 2 helps remove the hardware buffering abut
+the information is still very jittery, with up to one sample of
+error. In example 3 where the timestamps are measured with the link
+wallclock, the timestamps show a monotonic behavior and a lower
+dispersion.
+
+Example 3 and 4 are with USB audio class. Example 3 shows a high
+offset between audio time and system time due to buffering. Example 4
+shows how compensating for the delay exposes a 1ms accuracy (due to
+the use of the frame counter by the driver)
+
+Example 3: DMA timestamp, no compensation for delay, delta of ~5ms
+$ ./audio_time -p -Dhw:1 -t1
+playback: systime: 120174019 nsec, audio time 125000000 nsec, 	systime delta -4825981
+playback: systime: 245041136 nsec, audio time 250000000 nsec, 	systime delta -4958864
+playback: systime: 370106088 nsec, audio time 375000000 nsec, 	systime delta -4893912
+playback: systime: 495040065 nsec, audio time 500000000 nsec, 	systime delta -4959935
+playback: systime: 620038179 nsec, audio time 625000000 nsec, 	systime delta -4961821
+playback: systime: 745087741 nsec, audio time 750000000 nsec, 	systime delta -4912259
+playback: systime: 870037336 nsec, audio time 875000000 nsec, 	systime delta -4962664
+
+Example 4: DMA timestamp, compensation for delay, delay of ~1ms
+$ ./audio_time -p -Dhw:1 -t1 -d
+playback: systime: 120190520 nsec, audio time 120000000 nsec, 	systime delta 190520
+playback: systime: 245036740 nsec, audio time 244000000 nsec, 	systime delta 1036740
+playback: systime: 370034081 nsec, audio time 369000000 nsec, 	systime delta 1034081
+playback: systime: 495159907 nsec, audio time 494000000 nsec, 	systime delta 1159907
+playback: systime: 620098824 nsec, audio time 619000000 nsec, 	systime delta 1098824
+playback: systime: 745031847 nsec, audio time 744000000 nsec, 	systime delta 1031847
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index d315a08..0e9d75b 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -608,7 +608,9 @@
 	int type;		/* quirk type above */
 };
 
-int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override);
+int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
+			   const struct ac97_quirk *quirk,
+			   const char *override);
 int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate);
 
 /*
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index f48089d..fa1d055 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -70,7 +70,7 @@
  * @device: device pointer
  * @direction: stream direction, playback/recording
  * @metadata_set: metadata set flag, true when set
- * @next_track: has userspace signall next track transistion, true when set
+ * @next_track: has userspace signal next track transition, true when set
  * @private_data: pointer to DSP private data
  */
 struct snd_compr_stream {
@@ -95,7 +95,7 @@
  * and the stream properties
  * @get_params: retrieve the codec parameters, mandatory
  * @set_metadata: Set the metadata values for a stream
- * @get_metadata: retreives the requested metadata values from stream
+ * @get_metadata: retrieves the requested metadata values from stream
  * @trigger: Trigger operations like start, pause, resume, drain, stop.
  * This callback is mandatory
  * @pointer: Retrieve current h/w pointer information. Mandatory
diff --git a/include/sound/control.h b/include/sound/control.h
index 75f3054..95aad6d 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -227,7 +227,7 @@
  * Add a virtual slave control to the given master.
  * Unlike snd_ctl_add_slave(), the element added via this function
  * is supposed to have volatile values, and get callback is called
- * at each time quried from the master.
+ * at each time queried from the master.
  *
  * When the control peeks the hardware values directly and the value
  * can be changed by other means than the put callback of the element,
diff --git a/include/sound/core.h b/include/sound/core.h
index da57482..b12931f 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -278,7 +278,8 @@
 		   void *device_data, struct snd_device_ops *ops);
 int snd_device_register(struct snd_card *card, void *device_data);
 int snd_device_register_all(struct snd_card *card);
-int snd_device_disconnect_all(struct snd_card *card);
+void snd_device_disconnect(struct snd_card *card, void *device_data);
+void snd_device_disconnect_all(struct snd_card *card);
 void snd_device_free(struct snd_card *card, void *device_data);
 void snd_device_free_all(struct snd_card *card);
 
diff --git a/include/sound/hda_regmap.h b/include/sound/hda_regmap.h
new file mode 100644
index 0000000..53a18b3
--- /dev/null
+++ b/include/sound/hda_regmap.h
@@ -0,0 +1,217 @@
+/*
+ * HD-audio regmap helpers
+ */
+
+#ifndef __SOUND_HDA_REGMAP_H
+#define __SOUND_HDA_REGMAP_H
+
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+
+int snd_hdac_regmap_init(struct hdac_device *codec);
+void snd_hdac_regmap_exit(struct hdac_device *codec);
+int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
+				    unsigned int verb);
+int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
+			     unsigned int *val);
+int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
+			      unsigned int val);
+int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
+			       unsigned int mask, unsigned int val);
+
+/**
+ * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
+ * @nid: widget NID
+ * @verb: codec verb
+ *
+ * Returns an encoded pseudo register.
+ */
+#define snd_hdac_regmap_encode_verb(nid, verb)		\
+	(((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
+
+/**
+ * snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
+ * @nid: widget NID
+ * @ch: channel (left = 0, right = 1)
+ * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
+ * @idx: input index value
+ *
+ * Returns an encoded pseudo register.
+ */
+#define snd_hdac_regmap_encode_amp(nid, ch, dir, idx)			\
+	(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |	\
+	 ((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) |			\
+	 ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
+	 (idx))
+
+/**
+ * snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
+ * @nid: widget NID
+ * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
+ * @idx: input index value
+ *
+ * Returns an encoded pseudo register.
+ */
+#define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx)		\
+	(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |	\
+	 AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */	\
+	 ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
+	 (idx))
+
+/**
+ * snd_hdac_regmap_write - Write a verb with caching
+ * @nid: codec NID
+ * @reg: verb to write
+ * @val: value to write
+ *
+ * For writing an amp value, use snd_hda_regmap_amp_update().
+ */
+static inline int
+snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
+		      unsigned int verb, unsigned int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
+
+	return snd_hdac_regmap_write_raw(codec, cmd, val);
+}
+
+/**
+ * snd_hda_regmap_update - Update a verb value with caching
+ * @nid: codec NID
+ * @verb: verb to update
+ * @mask: bit mask to update
+ * @val: value to update
+ *
+ * For updating an amp value, use snd_hda_regmap_amp_update().
+ */
+static inline int
+snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
+		       unsigned int verb, unsigned int mask,
+		       unsigned int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
+
+	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
+}
+
+/**
+ * snd_hda_regmap_read - Read a verb with caching
+ * @nid: codec NID
+ * @verb: verb to read
+ * @val: pointer to store the value
+ *
+ * For reading an amp value, use snd_hda_regmap_get_amp().
+ */
+static inline int
+snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
+		     unsigned int verb, unsigned int *val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
+
+	return snd_hdac_regmap_read_raw(codec, cmd, val);
+}
+
+/**
+ * snd_hdac_regmap_get_amp - Read AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @index: the index value (only for input direction)
+ * @val: the pointer to store the value
+ *
+ * Read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
+ * Returns the value or a negative error.
+ */
+static inline int
+snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
+			int ch, int dir, int idx)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+	int err, val;
+
+	err = snd_hdac_regmap_read_raw(codec, cmd, &val);
+	return err < 0 ? err : val;
+}
+
+/**
+ * snd_hdac_regmap_update_amp - update the AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the AMP value with a bit mask.
+ * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ */
+static inline int
+snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
+			   int ch, int dir, int idx, int mask, int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+
+	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
+}
+
+/**
+ * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @index: the index value (only for input direction)
+ * @val: the pointer to store the value
+ *
+ * Read stereo AMP values.  The lower byte is left, the upper byte is right.
+ * Returns the value or a negative error.
+ */
+static inline int
+snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
+			       int dir, int idx)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
+	int err, val;
+
+	err = snd_hdac_regmap_read_raw(codec, cmd, &val);
+	return err < 0 ? err : val;
+}
+
+/**
+ * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the stereo AMP value with a bit mask.
+ * The lower byte is left, the upper byte is right.
+ * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ */
+static inline int
+snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
+				  int dir, int idx, int mask, int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
+
+	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
+}
+
+/**
+ * snd_hdac_regmap_sync_node - sync the widget node attributes
+ * @codec: HD-audio codec
+ * @nid: NID to sync
+ */
+static inline void
+snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
+{
+	regcache_mark_dirty(codec->regmap);
+	regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
+}
+
+#endif /* __SOUND_HDA_REGMAP_H */
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
new file mode 100644
index 0000000..2a8aa9d
--- /dev/null
+++ b/include/sound/hdaudio.h
@@ -0,0 +1,247 @@
+/*
+ * HD-audio core stuff
+ */
+
+#ifndef __SOUND_HDAUDIO_H
+#define __SOUND_HDAUDIO_H
+
+#include <linux/device.h>
+#include <sound/hda_verbs.h>
+
+/* codec node id */
+typedef u16 hda_nid_t;
+
+struct hdac_bus;
+struct hdac_device;
+struct hdac_driver;
+struct hdac_widget_tree;
+
+/*
+ * exported bus type
+ */
+extern struct bus_type snd_hda_bus_type;
+
+/*
+ * generic arrays
+ */
+struct snd_array {
+	unsigned int used;
+	unsigned int alloced;
+	unsigned int elem_size;
+	unsigned int alloc_align;
+	void *list;
+};
+
+/*
+ * HD-audio codec base device
+ */
+struct hdac_device {
+	struct device dev;
+	int type;
+	struct hdac_bus *bus;
+	unsigned int addr;		/* codec address */
+	struct list_head list;		/* list point for bus codec_list */
+
+	hda_nid_t afg;			/* AFG node id */
+	hda_nid_t mfg;			/* MFG node id */
+
+	/* ids */
+	unsigned int vendor_id;
+	unsigned int subsystem_id;
+	unsigned int revision_id;
+	unsigned int afg_function_id;
+	unsigned int mfg_function_id;
+	unsigned int afg_unsol:1;
+	unsigned int mfg_unsol:1;
+
+	unsigned int power_caps;	/* FG power caps */
+
+	const char *vendor_name;	/* codec vendor name */
+	const char *chip_name;		/* codec chip name */
+
+	/* verb exec op override */
+	int (*exec_verb)(struct hdac_device *dev, unsigned int cmd,
+			 unsigned int flags, unsigned int *res);
+
+	/* widgets */
+	unsigned int num_nodes;
+	hda_nid_t start_nid, end_nid;
+
+	/* misc flags */
+	atomic_t in_pm;		/* suspend/resume being performed */
+
+	/* sysfs */
+	struct hdac_widget_tree *widgets;
+
+	/* regmap */
+	struct regmap *regmap;
+	struct snd_array vendor_verbs;
+	bool lazy_cache:1;	/* don't wake up for writes */
+	bool caps_overwriting:1; /* caps overwrite being in process */
+	bool cache_coef:1;	/* cache COEF read/write too */
+};
+
+/* device/driver type used for matching */
+enum {
+	HDA_DEV_CORE,
+	HDA_DEV_LEGACY,
+};
+
+/* direction */
+enum {
+	HDA_INPUT, HDA_OUTPUT
+};
+
+#define dev_to_hdac_dev(_dev)	container_of(_dev, struct hdac_device, dev)
+
+int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
+			 const char *name, unsigned int addr);
+void snd_hdac_device_exit(struct hdac_device *dev);
+int snd_hdac_device_register(struct hdac_device *codec);
+void snd_hdac_device_unregister(struct hdac_device *codec);
+
+int snd_hdac_refresh_widgets(struct hdac_device *codec);
+
+unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
+			       unsigned int verb, unsigned int parm);
+int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
+		       unsigned int flags, unsigned int *res);
+int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
+		  unsigned int verb, unsigned int parm, unsigned int *res);
+int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
+			unsigned int *res);
+int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
+				int parm);
+int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
+			   unsigned int parm, unsigned int val);
+int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
+			     hda_nid_t *conn_list, int max_conns);
+int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
+			   hda_nid_t *start_id);
+
+/**
+ * snd_hdac_read_parm - read a codec parameter
+ * @codec: the codec object
+ * @nid: NID to read a parameter
+ * @parm: parameter to read
+ *
+ * Returns -1 for error.  If you need to distinguish the error more
+ * strictly, use _snd_hdac_read_parm() directly.
+ */
+static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
+				     int parm)
+{
+	unsigned int val;
+
+	return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val;
+}
+
+#ifdef CONFIG_PM
+void snd_hdac_power_up(struct hdac_device *codec);
+void snd_hdac_power_down(struct hdac_device *codec);
+void snd_hdac_power_up_pm(struct hdac_device *codec);
+void snd_hdac_power_down_pm(struct hdac_device *codec);
+#else
+static inline void snd_hdac_power_up(struct hdac_device *codec) {}
+static inline void snd_hdac_power_down(struct hdac_device *codec) {}
+static inline void snd_hdac_power_up_pm(struct hdac_device *codec) {}
+static inline void snd_hdac_power_down_pm(struct hdac_device *codec) {}
+#endif
+
+/*
+ * HD-audio codec base driver
+ */
+struct hdac_driver {
+	struct device_driver driver;
+	int type;
+	int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
+	void (*unsol_event)(struct hdac_device *dev, unsigned int event);
+};
+
+#define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
+
+/*
+ * HD-audio bus base driver
+ */
+struct hdac_bus_ops {
+	/* send a single command */
+	int (*command)(struct hdac_bus *bus, unsigned int cmd);
+	/* get a response from the last command */
+	int (*get_response)(struct hdac_bus *bus, unsigned int addr,
+			    unsigned int *res);
+};
+
+#define HDA_UNSOL_QUEUE_SIZE	64
+
+struct hdac_bus {
+	struct device *dev;
+	const struct hdac_bus_ops *ops;
+
+	/* codec linked list */
+	struct list_head codec_list;
+	unsigned int num_codecs;
+
+	/* link caddr -> codec */
+	struct hdac_device *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
+
+	/* unsolicited event queue */
+	u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
+	unsigned int unsol_rp, unsol_wp;
+	struct work_struct unsol_work;
+
+	/* bit flags of powered codecs */
+	unsigned long codec_powered;
+
+	/* flags */
+	bool sync_write:1;		/* sync after verb write */
+
+	/* locks */
+	struct mutex cmd_mutex;
+};
+
+int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
+		      const struct hdac_bus_ops *ops);
+void snd_hdac_bus_exit(struct hdac_bus *bus);
+int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
+			   unsigned int cmd, unsigned int *res);
+int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
+				    unsigned int cmd, unsigned int *res);
+void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
+
+int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
+void snd_hdac_bus_remove_device(struct hdac_bus *bus,
+				struct hdac_device *codec);
+
+static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
+{
+	set_bit(codec->addr, &codec->bus->codec_powered);
+}
+
+static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
+{
+	clear_bit(codec->addr, &codec->bus->codec_powered);
+}
+
+/*
+ * generic array helpers
+ */
+void *snd_array_new(struct snd_array *array);
+void snd_array_free(struct snd_array *array);
+static inline void snd_array_init(struct snd_array *array, unsigned int size,
+				  unsigned int align)
+{
+	array->elem_size = size;
+	array->alloc_align = align;
+}
+
+static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
+{
+	return array->list + idx * array->elem_size;
+}
+
+static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
+{
+	return (unsigned long)(ptr - array->list) / array->elem_size;
+}
+
+#endif /* __SOUND_HDAUDIO_H */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index c0ddb7e..0cb7f3f 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -60,6 +60,9 @@
 
 struct snd_pcm_substream;
 
+struct snd_pcm_audio_tstamp_config; /* definitions further down */
+struct snd_pcm_audio_tstamp_report;
+
 struct snd_pcm_ops {
 	int (*open)(struct snd_pcm_substream *substream);
 	int (*close)(struct snd_pcm_substream *substream);
@@ -71,8 +74,10 @@
 	int (*prepare)(struct snd_pcm_substream *substream);
 	int (*trigger)(struct snd_pcm_substream *substream, int cmd);
 	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
-	int (*wall_clock)(struct snd_pcm_substream *substream,
-			  struct timespec *audio_ts);
+	int (*get_time_info)(struct snd_pcm_substream *substream,
+			struct timespec *system_ts, struct timespec *audio_ts,
+			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
+			struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
 	int (*copy)(struct snd_pcm_substream *substream, int channel,
 		    snd_pcm_uframes_t pos,
 		    void __user *buf, snd_pcm_uframes_t count);
@@ -281,6 +286,58 @@
 
 struct snd_pcm_hwptr_log;
 
+/*
+ * userspace-provided audio timestamp config to kernel,
+ * structure is for internal use only and filled with dedicated unpack routine
+ */
+struct snd_pcm_audio_tstamp_config {
+	/* 5 of max 16 bits used */
+	u32 type_requested:4;
+	u32 report_delay:1; /* add total delay to A/D or D/A */
+};
+
+static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data,
+						struct snd_pcm_audio_tstamp_config *config)
+{
+	config->type_requested = data & 0xF;
+	config->report_delay = (data >> 4) & 1;
+}
+
+/*
+ * kernel-provided audio timestamp report to user-space
+ * structure is for internal use only and read by dedicated pack routine
+ */
+struct snd_pcm_audio_tstamp_report {
+	/* 6 of max 16 bits used for bit-fields */
+
+	/* for backwards compatibility */
+	u32 valid:1;
+
+	/* actual type if hardware could not support requested timestamp */
+	u32 actual_type:4;
+
+	/* accuracy represented in ns units */
+	u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
+	u32 accuracy; /* up to 4.29s, will be packed in separate field  */
+};
+
+static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy,
+						const struct snd_pcm_audio_tstamp_report *report)
+{
+	u32 tmp;
+
+	tmp = report->accuracy_report;
+	tmp <<= 4;
+	tmp |= report->actual_type;
+	tmp <<= 1;
+	tmp |= report->valid;
+
+	*data &= 0xffff; /* zero-clear MSBs */
+	*data |= (tmp << 16);
+	*accuracy = report->accuracy;
+}
+
+
 struct snd_pcm_runtime {
 	/* -- Status -- */
 	struct snd_pcm_substream *trigger_master;
@@ -361,6 +418,11 @@
 
 	struct snd_dma_buffer *dma_buffer_p;	/* allocated buffer */
 
+	/* -- audio timestamp config -- */
+	struct snd_pcm_audio_tstamp_config audio_tstamp_config;
+	struct snd_pcm_audio_tstamp_report audio_tstamp_report;
+	struct timespec driver_tstamp;
+
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	/* -- OSS things -- */
 	struct snd_pcm_oss_runtime oss;
diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h
index 2b5f24c..ddc0d50 100644
--- a/include/sound/seq_device.h
+++ b/include/sound/seq_device.h
@@ -25,29 +25,26 @@
  * registered device information
  */
 
-#define ID_LEN	32
-
-/* status flag */
-#define SNDRV_SEQ_DEVICE_FREE		0
-#define SNDRV_SEQ_DEVICE_REGISTERED	1
-
 struct snd_seq_device {
 	/* device info */
 	struct snd_card *card;	/* sound card */
 	int device;		/* device number */
-	char id[ID_LEN];	/* driver id */
+	const char *id;		/* driver id */
 	char name[80];		/* device name */
 	int argsize;		/* size of the argument */
 	void *driver_data;	/* private data for driver */
-	int status;		/* flag - read only */
 	void *private_data;	/* private data for the caller */
 	void (*private_free)(struct snd_seq_device *device);
-	struct list_head list;	/* link to next device */
+	struct device dev;
 };
 
+#define to_seq_dev(_dev) \
+	container_of(_dev, struct snd_seq_device, dev)
+
+/* sequencer driver */
 
 /* driver operators
- * init_device:
+ * probe:
  *	Initialize the device with given parameters.
  *	Typically,
  *		1. call snd_hwdep_new
@@ -55,25 +52,40 @@
  *		3. call snd_hwdep_register
  *		4. store the instance to dev->driver_data pointer.
  *		
- * free_device:
+ * remove:
  *	Release the private data.
  *	Typically, call snd_device_free(dev->card, dev->driver_data)
  */
-struct snd_seq_dev_ops {
-	int (*init_device)(struct snd_seq_device *dev);
-	int (*free_device)(struct snd_seq_device *dev);
+struct snd_seq_driver {
+	struct device_driver driver;
+	char *id;
+	int argsize;
 };
 
+#define to_seq_drv(_drv) \
+	container_of(_drv, struct snd_seq_driver, driver)
+
 /*
  * prototypes
  */
+#ifdef CONFIG_MODULES
 void snd_seq_device_load_drivers(void);
-int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result);
-int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize);
-int snd_seq_device_unregister_driver(char *id);
+#else
+#define snd_seq_device_load_drivers()
+#endif
+int snd_seq_device_new(struct snd_card *card, int device, const char *id,
+		       int argsize, struct snd_seq_device **result);
 
 #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device))
 
+int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv,
+					   struct module *mod);
+#define snd_seq_driver_register(drv) \
+	__snd_seq_driver_register(drv, THIS_MODULE)
+void snd_seq_driver_unregister(struct snd_seq_driver *drv);
+
+#define module_snd_seq_driver(drv) \
+	module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister)
 
 /*
  * id strings for generic devices
diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h
index 18a2ac5..feb58d4 100644
--- a/include/sound/seq_kernel.h
+++ b/include/sound/seq_kernel.h
@@ -99,13 +99,9 @@
 int snd_seq_event_port_detach(int client, int port);
 
 #ifdef CONFIG_MODULES
-void snd_seq_autoload_lock(void);
-void snd_seq_autoload_unlock(void);
 void snd_seq_autoload_init(void);
-#define snd_seq_autoload_exit()	snd_seq_autoload_lock()
+void snd_seq_autoload_exit(void);
 #else
-#define snd_seq_autoload_lock()
-#define snd_seq_autoload_unlock()
 #define snd_seq_autoload_init()
 #define snd_seq_autoload_exit()
 #endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2afdd2e..fcb312b 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1493,7 +1493,7 @@
 }
 
 /**
- * snd_soc_kcontrol_platform() - Returns the platform that registerd the control
+ * snd_soc_kcontrol_platform() - Returns the platform that registered the control
  * @kcontrol: The control for which to get the platform
  *
  * Note: This function will only work correctly if the control has been
diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h
index 09c8a00..5a5fa49 100644
--- a/include/uapi/sound/asequencer.h
+++ b/include/uapi/sound/asequencer.h
@@ -22,6 +22,7 @@
 #ifndef _UAPI__SOUND_ASEQUENCER_H
 #define _UAPI__SOUND_ASEQUENCER_H
 
+#include <sound/asound.h>
 
 /** version of the sequencer */
 #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 0e88e7a..46145a5 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -25,6 +25,9 @@
 
 #include <linux/types.h>
 
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
 
 /*
  *  protocol version
@@ -140,7 +143,7 @@
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 12)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 13)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -267,10 +270,17 @@
 #define SNDRV_PCM_INFO_JOINT_DUPLEX	0x00200000	/* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START	0x00400000	/* pcm support some kind of sync go */
 #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP	0x00800000	/* period wakeup can be disabled */
-#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* (Deprecated)has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_LINK_ATIME              0x01000000  /* report hardware link audio time, reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
+#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
+
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER	0x40000000		/* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
 
+
+
 typedef int __bitwise snd_pcm_state_t;
 #define	SNDRV_PCM_STATE_OPEN		((__force snd_pcm_state_t) 0) /* stream is open */
 #define	SNDRV_PCM_STATE_SETUP		((__force snd_pcm_state_t) 1) /* stream has a setup */
@@ -408,6 +418,22 @@
 	unsigned int step;		/* samples distance in bits */
 };
 
+enum {
+	/*
+	 *  first definition for backwards compatibility only,
+	 *  maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else
+	 */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0,
+
+	/* timestamp definitions */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1,           /* DMA time, reported as per hw_ptr */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2,	           /* link time reported by sample or wallclock counter, reset on startup */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3,	   /* link time reported by sample or wallclock counter, not reset on startup */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4,    /* link time estimated indirectly */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
+};
+
 struct snd_pcm_status {
 	snd_pcm_state_t state;		/* stream state */
 	struct timespec trigger_tstamp;	/* time when stream was started/stopped/paused */
@@ -419,9 +445,11 @@
 	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
 	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
 	snd_pcm_state_t suspended_state; /* suspended stream state */
-	__u32 reserved_alignment;	/* must be filled with zero */
-	struct timespec audio_tstamp;	/* from sample counter or wall clock */
-	unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
+	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
+	struct timespec audio_tstamp;	/* sample counter, wall clock, PHC or on-demand sync'ed */
+	struct timespec driver_tstamp;	/* useful in case reference system tstamp is reported with delay */
+	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
+	unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
 };
 
 struct snd_pcm_mmap_status {
@@ -534,6 +562,7 @@
 #define SNDRV_PCM_IOCTL_DELAY		_IOR('A', 0x21, snd_pcm_sframes_t)
 #define SNDRV_PCM_IOCTL_HWSYNC		_IO('A', 0x22)
 #define SNDRV_PCM_IOCTL_SYNC_PTR	_IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_STATUS_EXT	_IOWR('A', 0x24, struct snd_pcm_status)
 #define SNDRV_PCM_IOCTL_CHANNEL_INFO	_IOR('A', 0x32, struct snd_pcm_channel_info)
 #define SNDRV_PCM_IOCTL_PREPARE		_IO('A', 0x40)
 #define SNDRV_PCM_IOCTL_RESET		_IO('A', 0x41)
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index 22ed8cb..e00d8cb 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -75,7 +75,7 @@
 /**
  * struct snd_compr_avail - avail descriptor
  * @avail: Number of bytes available in ring buffer for writing/reading
- * @tstamp: timestamp infomation
+ * @tstamp: timestamp information
  */
 struct snd_compr_avail {
 	__u64 avail;
diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h
index d1bbaf7..ec1535b 100644
--- a/include/uapi/sound/emu10k1.h
+++ b/include/uapi/sound/emu10k1.h
@@ -23,8 +23,7 @@
 #define _UAPI__SOUND_EMU10K1_H
 
 #include <linux/types.h>
-
-
+#include <sound/asound.h>
 
 /*
  * ---- FX8010 ----
diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h
index b357f1a5..5737332 100644
--- a/include/uapi/sound/hdspm.h
+++ b/include/uapi/sound/hdspm.h
@@ -20,6 +20,12 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
 /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
 #define HDSPM_MAX_CHANNELS      64
 
diff --git a/sound/Kconfig b/sound/Kconfig
index c710ce2..5a240e0 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -76,6 +76,8 @@
 
 source "sound/pci/Kconfig"
 
+source "sound/hda/Kconfig"
+
 source "sound/ppc/Kconfig"
 
 source "sound/aoa/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index ce9132b..7732070 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -6,7 +6,7 @@
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
 obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
-	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
+	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index b9737fa..1cbf210 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -31,7 +31,7 @@
 MODULE_PARM_DESC(force, "Force loading i2sbus even when"
 			" no layout-id property is present");
 
-static struct of_device_id i2sbus_match[] = {
+static const struct of_device_id i2sbus_match[] = {
 	{ .name = "i2s" },
 	{ }
 };
diff --git a/sound/core/control.c b/sound/core/control.c
index eeb691d..196a6fe 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -192,36 +192,41 @@
 EXPORT_SYMBOL(snd_ctl_notify);
 
 /**
- * snd_ctl_new - create a control instance from the template
- * @control: the control template
- * @access: the default control access
+ * snd_ctl_new - create a new control instance with some elements
+ * @kctl: the pointer to store new control instance
+ * @count: the number of elements in this control
+ * @access: the default access flags for elements in this control
+ * @file: given when locking these elements
  *
- * Allocates a new struct snd_kcontrol instance and copies the given template 
- * to the new instance. It does not copy volatile data (access).
+ * Allocates a memory object for a new control instance. The instance has
+ * elements as many as the given number (@count). Each element has given
+ * access permissions (@access). Each element is locked when @file is given.
  *
- * Return: The pointer of the new instance, or %NULL on failure.
+ * Return: 0 on success, error code on failure
  */
-static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
-					unsigned int access)
+static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
+		       unsigned int access, struct snd_ctl_file *file)
 {
-	struct snd_kcontrol *kctl;
+	unsigned int size;
 	unsigned int idx;
 	
-	if (snd_BUG_ON(!control || !control->count))
-		return NULL;
+	if (count == 0 || count > MAX_CONTROL_COUNT)
+		return -EINVAL;
 
-	if (control->count > MAX_CONTROL_COUNT)
-		return NULL;
+	size  = sizeof(struct snd_kcontrol);
+	size += sizeof(struct snd_kcontrol_volatile) * count;
 
-	kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
-	if (kctl == NULL) {
-		pr_err("ALSA: Cannot allocate control instance\n");
-		return NULL;
+	*kctl = kzalloc(size, GFP_KERNEL);
+	if (!*kctl)
+		return -ENOMEM;
+
+	for (idx = 0; idx < count; idx++) {
+		(*kctl)->vd[idx].access = access;
+		(*kctl)->vd[idx].owner = file;
 	}
-	*kctl = *control;
-	for (idx = 0; idx < kctl->count; idx++)
-		kctl->vd[idx].access = access;
-	return kctl;
+	(*kctl)->count = count;
+
+	return 0;
 }
 
 /**
@@ -238,37 +243,53 @@
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
 				  void *private_data)
 {
-	struct snd_kcontrol kctl;
+	struct snd_kcontrol *kctl;
+	unsigned int count;
 	unsigned int access;
+	int err;
 	
 	if (snd_BUG_ON(!ncontrol || !ncontrol->info))
 		return NULL;
-	memset(&kctl, 0, sizeof(kctl));
-	kctl.id.iface = ncontrol->iface;
-	kctl.id.device = ncontrol->device;
-	kctl.id.subdevice = ncontrol->subdevice;
+
+	count = ncontrol->count;
+	if (count == 0)
+		count = 1;
+
+	access = ncontrol->access;
+	if (access == 0)
+		access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	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 |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
+
+	err = snd_ctl_new(&kctl, count, access, NULL);
+	if (err < 0)
+		return NULL;
+
+	/* The 'numid' member is decided when calling snd_ctl_add(). */
+	kctl->id.iface = ncontrol->iface;
+	kctl->id.device = ncontrol->device;
+	kctl->id.subdevice = ncontrol->subdevice;
 	if (ncontrol->name) {
-		strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
-		if (strcmp(ncontrol->name, kctl.id.name) != 0)
+		strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name));
+		if (strcmp(ncontrol->name, kctl->id.name) != 0)
 			pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
-				ncontrol->name, kctl.id.name);
+				ncontrol->name, kctl->id.name);
 	}
-	kctl.id.index = ncontrol->index;
-	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|
-				      SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
-	kctl.info = ncontrol->info;
-	kctl.get = ncontrol->get;
-	kctl.put = ncontrol->put;
-	kctl.tlv.p = ncontrol->tlv.p;
-	kctl.private_value = ncontrol->private_value;
-	kctl.private_data = private_data;
-	return snd_ctl_new(&kctl, access);
+	kctl->id.index = ncontrol->index;
+
+	kctl->info = ncontrol->info;
+	kctl->get = ncontrol->get;
+	kctl->put = ncontrol->put;
+	kctl->tlv.p = ncontrol->tlv.p;
+
+	kctl->private_value = ncontrol->private_value;
+	kctl->private_data = private_data;
+
+	return kctl;
 }
 EXPORT_SYMBOL(snd_ctl_new1);
 
@@ -557,6 +578,7 @@
  *
  * Finds the control instance with the given id, and activate or
  * inactivate the control together with notification, if changed.
+ * The given ID data is filled with full information.
  *
  * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
  */
@@ -586,6 +608,7 @@
 			goto unlock;
 		vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 	}
+	snd_ctl_build_ioff(id, kctl, index_offset);
 	ret = 1;
  unlock:
 	up_write(&card->controls_rwsem);
@@ -1006,7 +1029,7 @@
 struct user_element {
 	struct snd_ctl_elem_info info;
 	struct snd_card *card;
-	void *elem_data;		/* element data */
+	char *elem_data;		/* element data */
 	unsigned long elem_data_size;	/* size of element data in bytes */
 	void *tlv_data;			/* TLV data */
 	unsigned long tlv_data_size;	/* TLV data size */
@@ -1017,8 +1040,12 @@
 				  struct snd_ctl_elem_info *uinfo)
 {
 	struct user_element *ue = kcontrol->private_data;
+	unsigned int offset;
 
+	offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
 	*uinfo = ue->info;
+	snd_ctl_build_ioff(&uinfo->id, kcontrol, offset);
+
 	return 0;
 }
 
@@ -1028,10 +1055,13 @@
 	struct user_element *ue = kcontrol->private_data;
 	const char *names;
 	unsigned int item;
+	unsigned int offset;
 
 	item = uinfo->value.enumerated.item;
 
+	offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
 	*uinfo = ue->info;
+	snd_ctl_build_ioff(&uinfo->id, kcontrol, offset);
 
 	item = min(item, uinfo->value.enumerated.items - 1);
 	uinfo->value.enumerated.item = item;
@@ -1048,9 +1078,12 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct user_element *ue = kcontrol->private_data;
+	unsigned int size = ue->elem_data_size;
+	char *src = ue->elem_data +
+			snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
 
 	mutex_lock(&ue->card->user_ctl_lock);
-	memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
+	memcpy(&ucontrol->value, src, size);
 	mutex_unlock(&ue->card->user_ctl_lock);
 	return 0;
 }
@@ -1060,11 +1093,14 @@
 {
 	int change;
 	struct user_element *ue = kcontrol->private_data;
+	unsigned int size = ue->elem_data_size;
+	char *dst = ue->elem_data +
+			snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
 
 	mutex_lock(&ue->card->user_ctl_lock);
-	change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
+	change = memcmp(&ucontrol->value, dst, size) != 0;
 	if (change)
-		memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
+		memcpy(dst, &ucontrol->value, size);
 	mutex_unlock(&ue->card->user_ctl_lock);
 	return change;
 }
@@ -1078,7 +1114,7 @@
 	int change = 0;
 	void *new_data;
 
-	if (op_flag > 0) {
+	if (op_flag == SNDRV_CTL_TLV_OP_WRITE) {
 		if (size > 1024 * 128)	/* sane value */
 			return -EINVAL;
 
@@ -1161,84 +1197,103 @@
 static int snd_ctl_elem_add(struct snd_ctl_file *file,
 			    struct snd_ctl_elem_info *info, int replace)
 {
+	/* The capacity of struct snd_ctl_elem_value.value.*/
+	static const unsigned int value_sizes[] = {
+		[SNDRV_CTL_ELEM_TYPE_BOOLEAN]	= sizeof(long),
+		[SNDRV_CTL_ELEM_TYPE_INTEGER]	= sizeof(long),
+		[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int),
+		[SNDRV_CTL_ELEM_TYPE_BYTES]	= sizeof(unsigned char),
+		[SNDRV_CTL_ELEM_TYPE_IEC958]	= sizeof(struct snd_aes_iec958),
+		[SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
+	};
+	static const unsigned int max_value_counts[] = {
+		[SNDRV_CTL_ELEM_TYPE_BOOLEAN]	= 128,
+		[SNDRV_CTL_ELEM_TYPE_INTEGER]	= 128,
+		[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128,
+		[SNDRV_CTL_ELEM_TYPE_BYTES]	= 512,
+		[SNDRV_CTL_ELEM_TYPE_IEC958]	= 1,
+		[SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64,
+	};
 	struct snd_card *card = file->card;
-	struct snd_kcontrol kctl, *_kctl;
+	struct snd_kcontrol *kctl;
+	unsigned int count;
 	unsigned int access;
 	long private_size;
 	struct user_element *ue;
-	int idx, err;
+	unsigned int offset;
+	int err;
 
-	if (info->count < 1)
-		return -EINVAL;
 	if (!*info->id.name)
 		return -EINVAL;
 	if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
 		return -EINVAL;
-	access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-		(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
-				 SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-				 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
-	info->id.numid = 0;
-	memset(&kctl, 0, sizeof(kctl));
 
+	/* Delete a control to replace them if needed. */
 	if (replace) {
+		info->id.numid = 0;
 		err = snd_ctl_remove_user_ctl(file, &info->id);
 		if (err)
 			return err;
 	}
 
-	if (card->user_ctl_count >= MAX_USER_CONTROLS)
+	/*
+	 * The number of userspace controls are counted control by control,
+	 * not element by element.
+	 */
+	if (card->user_ctl_count + 1 > MAX_USER_CONTROLS)
 		return -ENOMEM;
 
-	memcpy(&kctl.id, &info->id, sizeof(info->id));
-	kctl.count = info->owner ? info->owner : 1;
-	access |= SNDRV_CTL_ELEM_ACCESS_USER;
-	if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
-		kctl.info = snd_ctl_elem_user_enum_info;
-	else
-		kctl.info = snd_ctl_elem_user_info;
-	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
-		kctl.get = snd_ctl_elem_user_get;
-	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
-		kctl.put = snd_ctl_elem_user_put;
-	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
-		kctl.tlv.c = snd_ctl_elem_user_tlv;
+	/* Check the number of elements for this userspace control. */
+	count = info->owner;
+	if (count == 0)
+		count = 1;
+
+	/* Arrange access permissions if needed. */
+	access = info->access;
+	if (access == 0)
+		access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
+	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
 		access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
-	}
-	switch (info->type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		private_size = sizeof(long);
-		if (info->count > 128)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-		private_size = sizeof(long long);
-		if (info->count > 64)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-		private_size = sizeof(unsigned int);
-		if (info->count > 128 || info->value.enumerated.items == 0)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_BYTES:
-		private_size = sizeof(unsigned char);
-		if (info->count > 512)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_IEC958:
-		private_size = sizeof(struct snd_aes_iec958);
-		if (info->count != 1)
-			return -EINVAL;
-		break;
-	default:
+	access |= SNDRV_CTL_ELEM_ACCESS_USER;
+
+	/*
+	 * Check information and calculate the size of data specific to
+	 * this userspace control.
+	 */
+	if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+	    info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64)
 		return -EINVAL;
-	}
-	private_size *= info->count;
-	ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
-	if (ue == NULL)
+	if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED &&
+	    info->value.enumerated.items == 0)
+		return -EINVAL;
+	if (info->count < 1 ||
+	    info->count > max_value_counts[info->type])
+		return -EINVAL;
+	private_size = value_sizes[info->type] * info->count;
+
+	/*
+	 * Keep memory object for this userspace control. After passing this
+	 * code block, the instance should be freed by snd_ctl_free_one().
+	 *
+	 * Note that these elements in this control are locked.
+	 */
+	err = snd_ctl_new(&kctl, count, access, file);
+	if (err < 0)
+		return err;
+	memcpy(&kctl->id, &info->id, sizeof(kctl->id));
+	kctl->private_data = kzalloc(sizeof(struct user_element) + private_size * count,
+				     GFP_KERNEL);
+	if (kctl->private_data == NULL) {
+		kfree(kctl);
 		return -ENOMEM;
+	}
+	kctl->private_free = snd_ctl_elem_user_free;
+
+	/* Set private data for this userspace control. */
+	ue = (struct user_element *)kctl->private_data;
 	ue->card = card;
 	ue->info = *info;
 	ue->info.access = 0;
@@ -1247,23 +1302,36 @@
 	if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
 		err = snd_ctl_elem_init_enum_names(ue);
 		if (err < 0) {
-			kfree(ue);
+			snd_ctl_free_one(kctl);
 			return err;
 		}
 	}
-	kctl.private_free = snd_ctl_elem_user_free;
-	_kctl = snd_ctl_new(&kctl, access);
-	if (_kctl == NULL) {
-		kfree(ue->priv_data);
-		kfree(ue);
-		return -ENOMEM;
-	}
-	_kctl->private_data = ue;
-	for (idx = 0; idx < _kctl->count; idx++)
-		_kctl->vd[idx].owner = file;
-	err = snd_ctl_add(card, _kctl);
+
+	/* Set callback functions. */
+	if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
+		kctl->info = snd_ctl_elem_user_enum_info;
+	else
+		kctl->info = snd_ctl_elem_user_info;
+	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
+		kctl->get = snd_ctl_elem_user_get;
+	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
+		kctl->put = snd_ctl_elem_user_put;
+	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+		kctl->tlv.c = snd_ctl_elem_user_tlv;
+
+	/* This function manage to free the instance on failure. */
+	err = snd_ctl_add(card, kctl);
 	if (err < 0)
 		return err;
+	offset = snd_ctl_get_ioff(kctl, &info->id);
+	snd_ctl_build_ioff(&info->id, kctl, offset);
+	/*
+	 * Here we cannot fill any field for the number of elements added by
+	 * this operation because there're no specific fields. The usage of
+	 * 'owner' field for this purpose may cause any bugs to userspace
+	 * applications because the field originally means PID of a process
+	 * which locks the element.
+	 */
 
 	down_write(&card->controls_rwsem);
 	card->user_ctl_count++;
@@ -1276,9 +1344,19 @@
 				 struct snd_ctl_elem_info __user *_info, int replace)
 {
 	struct snd_ctl_elem_info info;
+	int err;
+
 	if (copy_from_user(&info, _info, sizeof(info)))
 		return -EFAULT;
-	return snd_ctl_elem_add(file, &info, replace);
+	err = snd_ctl_elem_add(file, &info, replace);
+	if (err < 0)
+		return err;
+	if (copy_to_user(_info, &info, sizeof(info))) {
+		snd_ctl_remove_user_ctl(file, &info.id);
+		return -EFAULT;
+	}
+
+	return 0;
 }
 
 static int snd_ctl_elem_remove(struct snd_ctl_file *file,
@@ -1338,9 +1416,12 @@
 		goto __kctl_end;
 	}
 	vd = &kctl->vd[tlv.numid - kctl->id.numid];
-	if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
-	    (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
-	    (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
+	if ((op_flag == SNDRV_CTL_TLV_OP_READ &&
+	     (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
+	    (op_flag == SNDRV_CTL_TLV_OP_WRITE &&
+	     (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
+	    (op_flag == SNDRV_CTL_TLV_OP_CMD &&
+	     (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
 	    	err = -ENXIO;
 	    	goto __kctl_end;
 	}
@@ -1357,7 +1438,7 @@
 			return 0;
 		}
 	} else {
-		if (op_flag) {
+		if (op_flag != SNDRV_CTL_TLV_OP_READ) {
 			err = -ENXIO;
 			goto __kctl_end;
 		}
diff --git a/sound/core/device.c b/sound/core/device.c
index 41bec30..8918838 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -50,10 +50,8 @@
 	if (snd_BUG_ON(!card || !device_data || !ops))
 		return -ENXIO;
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (dev == NULL) {
-		dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
+	if (!dev)
 		return -ENOMEM;
-	}
 	INIT_LIST_HEAD(&dev->list);
 	dev->card = card;
 	dev->type = type;
@@ -73,7 +71,7 @@
 }
 EXPORT_SYMBOL(snd_device_new);
 
-static int __snd_device_disconnect(struct snd_device *dev)
+static void __snd_device_disconnect(struct snd_device *dev)
 {
 	if (dev->state == SNDRV_DEV_REGISTERED) {
 		if (dev->ops->dev_disconnect &&
@@ -81,7 +79,6 @@
 			dev_err(dev->card->dev, "device disconnect failure\n");
 		dev->state = SNDRV_DEV_DISCONNECTED;
 	}
-	return 0;
 }
 
 static void __snd_device_free(struct snd_device *dev)
@@ -109,6 +106,34 @@
 }
 
 /**
+ * snd_device_disconnect - disconnect the device
+ * @card: the card instance
+ * @device_data: the data pointer to disconnect
+ *
+ * Turns the device into the disconnection state, invoking
+ * dev_disconnect callback, if the device was already registered.
+ *
+ * Usually called from snd_card_disconnect().
+ *
+ * Return: Zero if successful, or a negative error code on failure or if the
+ * device not found.
+ */
+void snd_device_disconnect(struct snd_card *card, void *device_data)
+{
+	struct snd_device *dev;
+
+	if (snd_BUG_ON(!card || !device_data))
+		return;
+	dev = look_for_dev(card, device_data);
+	if (dev)
+		__snd_device_disconnect(dev);
+	else
+		dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n",
+			device_data, __builtin_return_address(0));
+}
+EXPORT_SYMBOL_GPL(snd_device_disconnect);
+
+/**
  * snd_device_free - release the device from the card
  * @card: the card instance
  * @device_data: the data pointer to release
@@ -195,18 +220,14 @@
  * disconnect all the devices on the card.
  * called from init.c
  */
-int snd_device_disconnect_all(struct snd_card *card)
+void snd_device_disconnect_all(struct snd_card *card)
 {
 	struct snd_device *dev;
-	int err = 0;
 
 	if (snd_BUG_ON(!card))
-		return -ENXIO;
-	list_for_each_entry_reverse(dev, &card->devices, list) {
-		if (__snd_device_disconnect(dev) < 0)
-			err = -ENXIO;
-	}
-	return err;
+		return;
+	list_for_each_entry_reverse(dev, &card->devices, list)
+		__snd_device_disconnect(dev);
 }
 
 /*
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 84244a5..51692c8 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -378,10 +378,8 @@
 	if (rhwdep)
 		*rhwdep = NULL;
 	hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
-	if (hwdep == NULL) {
-		dev_err(card->dev, "hwdep: cannot allocate\n");
+	if (!hwdep)
 		return -ENOMEM;
-	}
 
 	init_waitqueue_head(&hwdep->open_wait);
 	mutex_init(&hwdep->open_mutex);
diff --git a/sound/core/init.c b/sound/core/init.c
index 3541905..04734e0 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -400,7 +400,6 @@
 int snd_card_disconnect(struct snd_card *card)
 {
 	struct snd_monitor_file *mfile;
-	int err;
 
 	if (!card)
 		return -EINVAL;
@@ -445,9 +444,7 @@
 #endif
 
 	/* notify all devices that we are disconnected */
-	err = snd_device_disconnect_all(card);
-	if (err < 0)
-		dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
+	snd_device_disconnect_all(card);
 
 	snd_info_card_disconnect(card);
 	if (card->registered) {
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 5e6349f..056f8e2 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1212,10 +1212,8 @@
 			/* not changed */
 			goto __unlock;
 		tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
-		if (! tbl) {
-			pr_err("ALSA: mixer_oss: no memory\n");
+		if (!tbl)
 			goto __unlock;
-		}
 		tbl->oss_id = ch;
 		tbl->name = kstrdup(str, GFP_KERNEL);
 		if (! tbl->name) {
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 80423a4c..58550cc 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -854,7 +854,6 @@
 	params = kmalloc(sizeof(*params), GFP_KERNEL);
 	sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
 	if (!sw_params || !params || !sparams) {
-		pcm_dbg(substream->pcm, "No memory\n");
 		err = -ENOMEM;
 		goto failure;
 	}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 0345e53..b25bcf5 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -49,8 +49,6 @@
 	struct snd_pcm *pcm;
 
 	list_for_each_entry(pcm, &snd_pcm_devices, list) {
-		if (pcm->internal)
-			continue;
 		if (pcm->card == card && pcm->device == device)
 			return pcm;
 	}
@@ -62,8 +60,6 @@
 	struct snd_pcm *pcm;
 
 	list_for_each_entry(pcm, &snd_pcm_devices, list) {
-		if (pcm->internal)
-			continue;
 		if (pcm->card == card && pcm->device > device)
 			return pcm->device;
 		else if (pcm->card->number > card->number)
@@ -76,6 +72,9 @@
 {
 	struct snd_pcm *pcm;
 
+	if (newpcm->internal)
+		return 0;
+
 	list_for_each_entry(pcm, &snd_pcm_devices, list) {
 		if (pcm->card == newpcm->card && pcm->device == newpcm->device)
 			return -EBUSY;
@@ -344,11 +343,8 @@
 		return;
 
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		pcm_dbg(substream->pcm,
-			"snd_pcm_proc_info_read: cannot malloc\n");
+	if (!info)
 		return;
-	}
 
 	err = snd_pcm_info(substream, info);
 	if (err < 0) {
@@ -718,10 +714,8 @@
 	prev = NULL;
 	for (idx = 0, prev = NULL; idx < substream_count; idx++) {
 		substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-		if (substream == NULL) {
-			pcm_err(pcm, "Cannot allocate PCM substream\n");
+		if (!substream)
 			return -ENOMEM;
-		}
 		substream->pcm = pcm;
 		substream->pstr = pstr;
 		substream->number = idx;
@@ -775,13 +769,14 @@
 	if (rpcm)
 		*rpcm = NULL;
 	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
-	if (pcm == NULL) {
-		dev_err(card->dev, "Cannot allocate PCM\n");
+	if (!pcm)
 		return -ENOMEM;
-	}
 	pcm->card = card;
 	pcm->device = device;
 	pcm->internal = internal;
+	mutex_init(&pcm->open_mutex);
+	init_waitqueue_head(&pcm->open_wait);
+	INIT_LIST_HEAD(&pcm->list);
 	if (id)
 		strlcpy(pcm->id, id, sizeof(pcm->id));
 	if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
@@ -792,8 +787,6 @@
 		snd_pcm_free(pcm);
 		return err;
 	}
-	mutex_init(&pcm->open_mutex);
-	init_waitqueue_head(&pcm->open_wait);
 	if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
 		snd_pcm_free(pcm);
 		return err;
@@ -888,8 +881,9 @@
 
 	if (!pcm)
 		return 0;
-	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-		notify->n_unregister(pcm);
+	if (!pcm->internal) {
+		list_for_each_entry(notify, &snd_pcm_notify_list, list)
+			notify->n_unregister(pcm);
 	}
 	if (pcm->private_free)
 		pcm->private_free(pcm);
@@ -919,6 +913,9 @@
 
 	if (snd_BUG_ON(!pcm || !rsubstream))
 		return -ENXIO;
+	if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK &&
+		       stream != SNDRV_PCM_STREAM_CAPTURE))
+		return -EINVAL;
 	*rsubstream = NULL;
 	pstr = &pcm->streams[stream];
 	if (pstr->substream == NULL || pstr->substream_count == 0)
@@ -927,25 +924,14 @@
 	card = pcm->card;
 	prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
 
-	switch (stream) {
-	case SNDRV_PCM_STREAM_PLAYBACK:
-		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-			for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
-				if (SUBSTREAM_BUSY(substream))
-					return -EAGAIN;
-			}
+	if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
+		int opposite = !stream;
+
+		for (substream = pcm->streams[opposite].substream; substream;
+		     substream = substream->next) {
+			if (SUBSTREAM_BUSY(substream))
+				return -EAGAIN;
 		}
-		break;
-	case SNDRV_PCM_STREAM_CAPTURE:
-		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-			for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
-				if (SUBSTREAM_BUSY(substream))
-					return -EAGAIN;
-			}
-		}
-		break;
-	default:
-		return -EINVAL;
 	}
 
 	if (file->f_flags & O_APPEND) {
@@ -968,15 +954,12 @@
 		return 0;
 	}
 
-	if (prefer_subdevice >= 0) {
-		for (substream = pstr->substream; substream; substream = substream->next)
-			if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
-				goto __ok;
-	}
-	for (substream = pstr->substream; substream; substream = substream->next)
-		if (!SUBSTREAM_BUSY(substream))
+	for (substream = pstr->substream; substream; substream = substream->next) {
+		if (!SUBSTREAM_BUSY(substream) &&
+		    (prefer_subdevice == -1 ||
+		     substream->number == prefer_subdevice))
 			break;
-      __ok:
+	}
 	if (substream == NULL)
 		return -EAGAIN;
 
@@ -1086,15 +1069,16 @@
 	if (snd_BUG_ON(!device || !device->device_data))
 		return -ENXIO;
 	pcm = device->device_data;
+	if (pcm->internal)
+		return 0;
+
 	mutex_lock(&register_mutex);
 	err = snd_pcm_add(pcm);
-	if (err) {
-		mutex_unlock(&register_mutex);
-		return err;
-	}
+	if (err)
+		goto unlock;
 	for (cidx = 0; cidx < 2; cidx++) {
 		int devtype = -1;
-		if (pcm->streams[cidx].substream == NULL || pcm->internal)
+		if (pcm->streams[cidx].substream == NULL)
 			continue;
 		switch (cidx) {
 		case SNDRV_PCM_STREAM_PLAYBACK:
@@ -1109,9 +1093,8 @@
 					  &snd_pcm_f_ops[cidx], pcm,
 					  &pcm->streams[cidx].dev);
 		if (err < 0) {
-			list_del(&pcm->list);
-			mutex_unlock(&register_mutex);
-			return err;
+			list_del_init(&pcm->list);
+			goto unlock;
 		}
 
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -1121,8 +1104,9 @@
 	list_for_each_entry(notify, &snd_pcm_notify_list, list)
 		notify->n_register(pcm);
 
+ unlock:
 	mutex_unlock(&register_mutex);
-	return 0;
+	return err;
 }
 
 static int snd_pcm_dev_disconnect(struct snd_device *device)
@@ -1133,13 +1117,10 @@
 	int cidx;
 
 	mutex_lock(&register_mutex);
-	if (list_empty(&pcm->list))
-		goto unlock;
-
 	mutex_lock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	list_del_init(&pcm->list);
-	for (cidx = 0; cidx < 2; cidx++)
+	for (cidx = 0; cidx < 2; cidx++) {
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
 			snd_pcm_stream_lock_irq(substream);
 			if (substream->runtime) {
@@ -1149,18 +1130,20 @@
 			}
 			snd_pcm_stream_unlock_irq(substream);
 		}
-	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-		notify->n_disconnect(pcm);
+	}
+	if (!pcm->internal) {
+		list_for_each_entry(notify, &snd_pcm_notify_list, list)
+			notify->n_disconnect(pcm);
 	}
 	for (cidx = 0; cidx < 2; cidx++) {
-		snd_unregister_device(&pcm->streams[cidx].dev);
+		if (!pcm->internal)
+			snd_unregister_device(&pcm->streams[cidx].dev);
 		if (pcm->streams[cidx].chmap_kctl) {
 			snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
 			pcm->streams[cidx].chmap_kctl = NULL;
 		}
 	}
 	mutex_unlock(&pcm->open_mutex);
- unlock:
 	mutex_unlock(&register_mutex);
 	return 0;
 }
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 2d957ba..b48b434 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -194,18 +194,30 @@
 	u32 avail_max;
 	u32 overrange;
 	s32 suspended_state;
-	u32 reserved_alignment;
+	u32 audio_tstamp_data;
 	struct compat_timespec audio_tstamp;
-	unsigned char reserved[56-sizeof(struct compat_timespec)];
+	struct compat_timespec driver_tstamp;
+	u32 audio_tstamp_accuracy;
+	unsigned char reserved[52-2*sizeof(struct compat_timespec)];
 } __attribute__((packed));
 
 
 static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
-				      struct snd_pcm_status32 __user *src)
+				      struct snd_pcm_status32 __user *src,
+				      bool ext)
 {
 	struct snd_pcm_status status;
 	int err;
 
+	memset(&status, 0, sizeof(status));
+	/*
+	 * with extension, parameters are read/write,
+	 * get audio_tstamp_data from user,
+	 * ignore rest of status structure
+	 */
+	if (ext && get_user(status.audio_tstamp_data,
+				(u32 __user *)(&src->audio_tstamp_data)))
+		return -EFAULT;
 	err = snd_pcm_status(substream, &status);
 	if (err < 0)
 		return err;
@@ -222,7 +234,10 @@
 	    put_user(status.avail_max, &src->avail_max) ||
 	    put_user(status.overrange, &src->overrange) ||
 	    put_user(status.suspended_state, &src->suspended_state) ||
-	    compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp))
+	    put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
+	    compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
+	    compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
+	    put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
 		return -EFAULT;
 
 	return err;
@@ -457,6 +472,7 @@
 	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
 	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
 	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
+	SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
 	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
 	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
 	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
@@ -517,7 +533,9 @@
 	case SNDRV_PCM_IOCTL_SW_PARAMS32:
 		return snd_pcm_ioctl_sw_params_compat(substream, argp);
 	case SNDRV_PCM_IOCTL_STATUS32:
-		return snd_pcm_status_user_compat(substream, argp);
+		return snd_pcm_status_user_compat(substream, argp, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT32:
+		return snd_pcm_status_user_compat(substream, argp, true);
 	case SNDRV_PCM_IOCTL_SYNC_PTR32:
 		return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 6542c40..fba365a 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -289,7 +289,7 @@
  *
  * The function should usually be called from the pcm open callback. Note that
  * this function will use private_data field of the substream's runtime. So it
- * is not availabe to your pcm driver implementation.
+ * is not available to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 	struct dma_chan *chan)
@@ -328,7 +328,7 @@
  * This function will request a DMA channel using the passed filter function and
  * data. The function should usually be called from the pcm open callback. Note
  * that this function will use private_data field of the substream's runtime. So
- * it is not availabe to your pcm driver implementation.
+ * it is not available to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
 	dma_filter_fn filter_fn, void *filter_data)
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index ffd6560..ac6b33f 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -232,6 +232,49 @@
 	return 0;
 }
 
+static void update_audio_tstamp(struct snd_pcm_substream *substream,
+				struct timespec *curr_tstamp,
+				struct timespec *audio_tstamp)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u64 audio_frames, audio_nsecs;
+	struct timespec driver_tstamp;
+
+	if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
+		return;
+
+	if (!(substream->ops->get_time_info) ||
+		(runtime->audio_tstamp_report.actual_type ==
+			SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
+
+		/*
+		 * provide audio timestamp derived from pointer position
+		 * add delay only if requested
+		 */
+
+		audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr;
+
+		if (runtime->audio_tstamp_config.report_delay) {
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				audio_frames -=  runtime->delay;
+			else
+				audio_frames +=  runtime->delay;
+		}
+		audio_nsecs = div_u64(audio_frames * 1000000000LL,
+				runtime->rate);
+		*audio_tstamp = ns_to_timespec(audio_nsecs);
+	}
+	runtime->status->audio_tstamp = *audio_tstamp;
+	runtime->status->tstamp = *curr_tstamp;
+
+	/*
+	 * re-take a driver timestamp to let apps detect if the reference tstamp
+	 * read by low-level hardware was provided with a delay
+	 */
+	snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp);
+	runtime->driver_tstamp = driver_tstamp;
+}
+
 static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 				  unsigned int in_interrupt)
 {
@@ -256,11 +299,18 @@
 	pos = substream->ops->pointer(substream);
 	curr_jiffies = jiffies;
 	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-		snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
+		if ((substream->ops->get_time_info) &&
+			(runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
+			substream->ops->get_time_info(substream, &curr_tstamp,
+						&audio_tstamp,
+						&runtime->audio_tstamp_config,
+						&runtime->audio_tstamp_report);
 
-		if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
-			(substream->ops->wall_clock))
-			substream->ops->wall_clock(substream, &audio_tstamp);
+			/* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
+			if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
+				snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
+		} else
+			snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
 	}
 
 	if (pos == SNDRV_PCM_POS_XRUN) {
@@ -403,8 +453,10 @@
 	}
 
  no_delta_check:
-	if (runtime->status->hw_ptr == new_hw_ptr)
+	if (runtime->status->hw_ptr == new_hw_ptr) {
+		update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
 		return 0;
+	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
@@ -426,30 +478,8 @@
 		snd_BUG_ON(crossed_boundary != 1);
 		runtime->hw_ptr_wrap += runtime->boundary;
 	}
-	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-		runtime->status->tstamp = curr_tstamp;
 
-		if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
-			/*
-			 * no wall clock available, provide audio timestamp
-			 * derived from pointer position+delay
-			 */
-			u64 audio_frames, audio_nsecs;
-
-			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-				audio_frames = runtime->hw_ptr_wrap
-					+ runtime->status->hw_ptr
-					- runtime->delay;
-			else
-				audio_frames = runtime->hw_ptr_wrap
-					+ runtime->status->hw_ptr
-					+ runtime->delay;
-			audio_nsecs = div_u64(audio_frames * 1000000000LL,
-					runtime->rate);
-			audio_tstamp = ns_to_timespec(audio_nsecs);
-		}
-		runtime->status->audio_tstamp = audio_tstamp;
-	}
+	update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
 
 	return snd_pcm_update_state(substream, runtime);
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 279e24f..abe1e81 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -707,6 +707,23 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	snd_pcm_stream_lock_irq(substream);
+
+	snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
+					&runtime->audio_tstamp_config);
+
+	/* backwards compatible behavior */
+	if (runtime->audio_tstamp_config.type_requested ==
+		SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) {
+		if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)
+			runtime->audio_tstamp_config.type_requested =
+				SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
+		else
+			runtime->audio_tstamp_config.type_requested =
+				SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
+		runtime->audio_tstamp_report.valid = 0;
+	} else
+		runtime->audio_tstamp_report.valid = 1;
+
 	status->state = runtime->status->state;
 	status->suspended_state = runtime->status->suspended_state;
 	if (status->state == SNDRV_PCM_STATE_OPEN)
@@ -716,8 +733,15 @@
 		snd_pcm_update_hw_ptr(substream);
 		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
 			status->tstamp = runtime->status->tstamp;
+			status->driver_tstamp = runtime->driver_tstamp;
 			status->audio_tstamp =
 				runtime->status->audio_tstamp;
+			if (runtime->audio_tstamp_report.valid == 1)
+				/* backwards compatibility, no report provided in COMPAT mode */
+				snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
+								&status->audio_tstamp_accuracy,
+								&runtime->audio_tstamp_report);
+
 			goto _tstamp_end;
 		}
 	} else {
@@ -753,12 +777,21 @@
 }
 
 static int snd_pcm_status_user(struct snd_pcm_substream *substream,
-			       struct snd_pcm_status __user * _status)
+			       struct snd_pcm_status __user * _status,
+			       bool ext)
 {
 	struct snd_pcm_status status;
 	int res;
-	
+
 	memset(&status, 0, sizeof(status));
+	/*
+	 * with extension, parameters are read/write,
+	 * get audio_tstamp_data from user,
+	 * ignore rest of status structure
+	 */
+	if (ext && get_user(status.audio_tstamp_data,
+				(u32 __user *)(&_status->audio_tstamp_data)))
+		return -EFAULT;
 	res = snd_pcm_status(substream, &status);
 	if (res < 0)
 		return res;
@@ -2725,7 +2758,9 @@
 	case SNDRV_PCM_IOCTL_SW_PARAMS:
 		return snd_pcm_sw_params_user(substream, arg);
 	case SNDRV_PCM_IOCTL_STATUS:
-		return snd_pcm_status_user(substream, arg);
+		return snd_pcm_status_user(substream, arg, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT:
+		return snd_pcm_status_user(substream, arg, true);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
 		return snd_pcm_channel_info_user(substream, arg);
 	case SNDRV_PCM_IOCTL_PREPARE:
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index b5a7485..a775984 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1429,10 +1429,8 @@
 
 	for (idx = 0; idx < count; idx++) {
 		substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-		if (substream == NULL) {
-			rmidi_err(rmidi, "rawmidi: cannot allocate substream\n");
+		if (!substream)
 			return -ENOMEM;
-		}
 		substream->stream = direction;
 		substream->number = idx;
 		substream->rmidi = rmidi;
@@ -1479,10 +1477,8 @@
 	if (rrawmidi)
 		*rrawmidi = NULL;
 	rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
-	if (rmidi == NULL) {
-		dev_err(card->dev, "rawmidi: cannot allocate\n");
+	if (!rmidi)
 		return -ENOMEM;
-	}
 	rmidi->card = card;
 	rmidi->device = device;
 	mutex_init(&rmidi->open_mutex);
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 16d4267..72873a4 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -65,15 +65,20 @@
  * module interface
  */
 
+static struct snd_seq_driver seq_oss_synth_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_seq_oss_synth_probe,
+		.remove = snd_seq_oss_synth_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_OSS,
+	.argsize = sizeof(struct snd_seq_oss_reg),
+};
+
 static int __init alsa_seq_oss_init(void)
 {
 	int rc;
-	static struct snd_seq_dev_ops ops = {
-		snd_seq_oss_synth_register,
-		snd_seq_oss_synth_unregister,
-	};
 
-	snd_seq_autoload_lock();
 	if ((rc = register_device()) < 0)
 		goto error;
 	if ((rc = register_proc()) < 0) {
@@ -86,8 +91,8 @@
 		goto error;
 	}
 
-	if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops,
-						 sizeof(struct snd_seq_oss_reg))) < 0) {
+	rc = snd_seq_driver_register(&seq_oss_synth_driver);
+	if (rc < 0) {
 		snd_seq_oss_delete_client();
 		unregister_proc();
 		unregister_device();
@@ -98,13 +103,12 @@
 	snd_seq_oss_synth_init();
 
  error:
-	snd_seq_autoload_unlock();
 	return rc;
 }
 
 static void __exit alsa_seq_oss_exit(void)
 {
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS);
+	snd_seq_driver_unregister(&seq_oss_synth_driver);
 	snd_seq_oss_delete_client();
 	unregister_proc();
 	unregister_device();
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index b0e32e1..2de3fef 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -188,10 +188,8 @@
 	struct seq_oss_devinfo *dp;
 
 	dp = kzalloc(sizeof(*dp), GFP_KERNEL);
-	if (!dp) {
-		pr_err("ALSA: seq_oss: can't malloc device info\n");
+	if (!dp)
 		return -ENOMEM;
-	}
 
 	dp->cseq = system_client;
 	dp->port = -1;
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index e79cc44..96e8395 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -173,10 +173,9 @@
 	/*
 	 * allocate midi info record
 	 */
-	if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc midi info\n");
+	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+	if (!mdev)
 		return -ENOMEM;
-	}
 
 	/* copy the port information */
 	mdev->client = pinfo->addr.client;
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
index 654d17a..c080c73 100644
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -47,13 +47,12 @@
 {
 	struct seq_oss_readq *q;
 
-	if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc read queue\n");
+	q = kzalloc(sizeof(*q), GFP_KERNEL);
+	if (!q)
 		return NULL;
-	}
 
-	if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc read queue buffer\n");
+	q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL);
+	if (!q->q) {
 		kfree(q);
 		return NULL;
 	}
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index 701feb7..48e4fe1 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -98,17 +98,17 @@
  * registration of the synth device
  */
 int
-snd_seq_oss_synth_register(struct snd_seq_device *dev)
+snd_seq_oss_synth_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	int i;
 	struct seq_oss_synth *rec;
 	struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
 	unsigned long flags;
 
-	if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc synth info\n");
+	rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+	if (!rec)
 		return -ENOMEM;
-	}
 	rec->seq_device = -1;
 	rec->synth_type = reg->type;
 	rec->synth_subtype = reg->subtype;
@@ -149,8 +149,9 @@
 
 
 int
-snd_seq_oss_synth_unregister(struct snd_seq_device *dev)
+snd_seq_oss_synth_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	int index;
 	struct seq_oss_synth *rec = dev->driver_data;
 	unsigned long flags;
@@ -247,7 +248,6 @@
 		if (info->nr_voices > 0) {
 			info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
 			if (!info->ch) {
-				pr_err("ALSA: seq_oss: Cannot malloc voices\n");
 				rec->oper.close(&info->arg);
 				module_put(rec->oper.owner);
 				snd_use_lock_free(&rec->use_lock);
diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h
index dbdfcbb..74ac55f 100644
--- a/sound/core/seq/oss/seq_oss_synth.h
+++ b/sound/core/seq/oss/seq_oss_synth.h
@@ -28,8 +28,8 @@
 #include <sound/seq_device.h>
 
 void snd_seq_oss_synth_init(void);
-int snd_seq_oss_synth_register(struct snd_seq_device *dev);
-int snd_seq_oss_synth_unregister(struct snd_seq_device *dev);
+int snd_seq_oss_synth_probe(struct device *dev);
+int snd_seq_oss_synth_remove(struct device *dev);
 void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp);
 void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp);
 void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp);
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 4828765..edbdab8 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1879,6 +1879,7 @@
 	if (cptr == NULL)
 		return -ENOENT;
 	memset(&info, 0, sizeof(info));
+	info.client = cptr->number;
 	info.output_pool = cptr->pool->size;
 	info.output_room = cptr->pool->room;
 	info.output_free = info.output_pool;
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 0631bda..d99f99d 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -36,6 +36,7 @@
  *
  */
 
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <sound/core.h>
@@ -51,140 +52,78 @@
 MODULE_DESCRIPTION("ALSA sequencer device management");
 MODULE_LICENSE("GPL");
 
-/* driver state */
-#define DRIVER_EMPTY		0
-#define DRIVER_LOADED		(1<<0)
-#define DRIVER_REQUESTED	(1<<1)
-#define DRIVER_LOCKED		(1<<2)
-#define DRIVER_REQUESTING	(1<<3)
+/*
+ * bus definition
+ */
+static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+	struct snd_seq_driver *sdrv = to_seq_drv(drv);
 
-struct ops_list {
-	char id[ID_LEN];	/* driver id */
-	int driver;		/* driver state */
-	int used;		/* reference counter */
-	int argsize;		/* argument size */
+	return strcmp(sdrv->id, sdev->id) == 0 &&
+		sdrv->argsize == sdev->argsize;
+}
 
-	/* operators */
-	struct snd_seq_dev_ops ops;
-
-	/* registered devices */
-	struct list_head dev_list;	/* list of devices */
-	int num_devices;	/* number of associated devices */
-	int num_init_devices;	/* number of initialized devices */
-	struct mutex reg_mutex;
-
-	struct list_head list;	/* next driver */
+static struct bus_type snd_seq_bus_type = {
+	.name = "snd_seq",
+	.match = snd_seq_bus_match,
 };
 
-
-static LIST_HEAD(opslist);
-static int num_ops;
-static DEFINE_MUTEX(ops_mutex);
+/*
+ * proc interface -- just for compatibility
+ */
 #ifdef CONFIG_PROC_FS
 static struct snd_info_entry *info_entry;
-#endif
 
-/*
- * prototypes
- */
-static int snd_seq_device_free(struct snd_seq_device *dev);
-static int snd_seq_device_dev_free(struct snd_device *device);
-static int snd_seq_device_dev_register(struct snd_device *device);
-static int snd_seq_device_dev_disconnect(struct snd_device *device);
+static int print_dev_info(struct device *dev, void *data)
+{
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+	struct snd_info_buffer *buffer = data;
 
-static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
-static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
-static struct ops_list *find_driver(char *id, int create_if_empty);
-static struct ops_list *create_driver(char *id);
-static void unlock_driver(struct ops_list *ops);
-static void remove_drivers(void);
+	snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id,
+		    dev->driver ? "loaded" : "empty",
+		    dev->driver ? 1 : 0);
+	return 0;
+}
 
-/*
- * show all drivers and their status
- */
-
-#ifdef CONFIG_PROC_FS
 static void snd_seq_device_info(struct snd_info_entry *entry,
 				struct snd_info_buffer *buffer)
 {
-	struct ops_list *ops;
-
-	mutex_lock(&ops_mutex);
-	list_for_each_entry(ops, &opslist, list) {
-		snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
-				ops->id,
-				ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
-				ops->driver & DRIVER_REQUESTED ? ",requested" : "",
-				ops->driver & DRIVER_LOCKED ? ",locked" : "",
-				ops->num_devices);
-	}
-	mutex_unlock(&ops_mutex);
+	bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
 }
 #endif
- 
+
 /*
  * load all registered drivers (called from seq_clientmgr.c)
  */
 
 #ifdef CONFIG_MODULES
-/* avoid auto-loading during module_init() */
+/* flag to block auto-loading */
 static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
-void snd_seq_autoload_lock(void)
+
+static int request_seq_drv(struct device *dev, void *data)
 {
-	atomic_inc(&snd_seq_in_init);
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+
+	if (!dev->driver)
+		request_module("snd-%s", sdev->id);
+	return 0;
 }
 
-void snd_seq_autoload_unlock(void)
-{
-	atomic_dec(&snd_seq_in_init);
-}
-
-static void autoload_drivers(void)
+static void autoload_drivers(struct work_struct *work)
 {
 	/* avoid reentrance */
-	if (atomic_inc_return(&snd_seq_in_init) == 1) {
-		struct ops_list *ops;
-
-		mutex_lock(&ops_mutex);
-		list_for_each_entry(ops, &opslist, list) {
-			if ((ops->driver & DRIVER_REQUESTING) &&
-			    !(ops->driver & DRIVER_REQUESTED)) {
-				ops->used++;
-				mutex_unlock(&ops_mutex);
-				ops->driver |= DRIVER_REQUESTED;
-				request_module("snd-%s", ops->id);
-				mutex_lock(&ops_mutex);
-				ops->used--;
-			}
-		}
-		mutex_unlock(&ops_mutex);
-	}
+	if (atomic_inc_return(&snd_seq_in_init) == 1)
+		bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
+				 request_seq_drv);
 	atomic_dec(&snd_seq_in_init);
 }
 
-static void call_autoload(struct work_struct *work)
-{
-	autoload_drivers();
-}
-
-static DECLARE_WORK(autoload_work, call_autoload);
-
-static void try_autoload(struct ops_list *ops)
-{
-	if (!ops->driver) {
-		ops->driver |= DRIVER_REQUESTING;
-		schedule_work(&autoload_work);
-	}
-}
+static DECLARE_WORK(autoload_work, autoload_drivers);
 
 static void queue_autoload_drivers(void)
 {
-	struct ops_list *ops;
-
-	mutex_lock(&ops_mutex);
-	list_for_each_entry(ops, &opslist, list)
-		try_autoload(ops);
-	mutex_unlock(&ops_mutex);
+	schedule_work(&autoload_work);
 }
 
 void snd_seq_autoload_init(void)
@@ -195,16 +134,63 @@
 	queue_autoload_drivers();
 #endif
 }
-#else
-#define try_autoload(ops) /* NOP */
-#endif
+EXPORT_SYMBOL(snd_seq_autoload_init);
+
+void snd_seq_autoload_exit(void)
+{
+	atomic_inc(&snd_seq_in_init);
+}
+EXPORT_SYMBOL(snd_seq_autoload_exit);
 
 void snd_seq_device_load_drivers(void)
 {
-#ifdef CONFIG_MODULES
 	queue_autoload_drivers();
 	flush_work(&autoload_work);
+}
+EXPORT_SYMBOL(snd_seq_device_load_drivers);
+#else
+#define queue_autoload_drivers() /* NOP */
 #endif
+
+/*
+ * device management
+ */
+static int snd_seq_device_dev_free(struct snd_device *device)
+{
+	struct snd_seq_device *dev = device->device_data;
+
+	put_device(&dev->dev);
+	return 0;
+}
+
+static int snd_seq_device_dev_register(struct snd_device *device)
+{
+	struct snd_seq_device *dev = device->device_data;
+	int err;
+
+	err = device_add(&dev->dev);
+	if (err < 0)
+		return err;
+	if (!dev->dev.driver)
+		queue_autoload_drivers();
+	return 0;
+}
+
+static int snd_seq_device_dev_disconnect(struct snd_device *device)
+{
+	struct snd_seq_device *dev = device->device_data;
+
+	device_del(&dev->dev);
+	return 0;
+}
+
+static void snd_seq_dev_release(struct device *dev)
+{
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+
+	if (sdev->private_free)
+		sdev->private_free(sdev);
+	kfree(sdev);
 }
 
 /*
@@ -214,11 +200,10 @@
  * id = id of driver
  * result = return pointer (NULL allowed if unnecessary)
  */
-int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
-		       struct snd_seq_device **result)
+int snd_seq_device_new(struct snd_card *card, int device, const char *id,
+		       int argsize, struct snd_seq_device **result)
 {
 	struct snd_seq_device *dev;
-	struct ops_list *ops;
 	int err;
 	static struct snd_device_ops dops = {
 		.dev_free = snd_seq_device_dev_free,
@@ -232,347 +217,60 @@
 	if (snd_BUG_ON(!id))
 		return -EINVAL;
 
-	ops = find_driver(id, 1);
-	if (ops == NULL)
+	dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
+	if (!dev)
 		return -ENOMEM;
 
-	dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);
-	if (dev == NULL) {
-		unlock_driver(ops);
-		return -ENOMEM;
-	}
-
 	/* set up device info */
 	dev->card = card;
 	dev->device = device;
-	strlcpy(dev->id, id, sizeof(dev->id));
+	dev->id = id;
 	dev->argsize = argsize;
-	dev->status = SNDRV_SEQ_DEVICE_FREE;
+
+	device_initialize(&dev->dev);
+	dev->dev.parent = &card->card_dev;
+	dev->dev.bus = &snd_seq_bus_type;
+	dev->dev.release = snd_seq_dev_release;
+	dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device);
 
 	/* add this device to the list */
-	mutex_lock(&ops->reg_mutex);
-	list_add_tail(&dev->list, &ops->dev_list);
-	ops->num_devices++;
-	mutex_unlock(&ops->reg_mutex);
-
-	if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
-		snd_seq_device_free(dev);
+	err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops);
+	if (err < 0) {
+		put_device(&dev->dev);
 		return err;
 	}
 	
-	try_autoload(ops);
-	unlock_driver(ops);
-
 	if (result)
 		*result = dev;
 
 	return 0;
 }
+EXPORT_SYMBOL(snd_seq_device_new);
 
 /*
- * free the existing device
+ * driver registration
  */
-static int snd_seq_device_free(struct snd_seq_device *dev)
+int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod)
 {
-	struct ops_list *ops;
-
-	if (snd_BUG_ON(!dev))
+	if (WARN_ON(!drv->driver.name || !drv->id))
 		return -EINVAL;
-
-	ops = find_driver(dev->id, 0);
-	if (ops == NULL)
-		return -ENXIO;
-
-	/* remove the device from the list */
-	mutex_lock(&ops->reg_mutex);
-	list_del(&dev->list);
-	ops->num_devices--;
-	mutex_unlock(&ops->reg_mutex);
-
-	free_device(dev, ops);
-	if (dev->private_free)
-		dev->private_free(dev);
-	kfree(dev);
-
-	unlock_driver(ops);
-
-	return 0;
+	drv->driver.bus = &snd_seq_bus_type;
+	drv->driver.owner = mod;
+	return driver_register(&drv->driver);
 }
+EXPORT_SYMBOL_GPL(__snd_seq_driver_register);
 
-static int snd_seq_device_dev_free(struct snd_device *device)
+void snd_seq_driver_unregister(struct snd_seq_driver *drv)
 {
-	struct snd_seq_device *dev = device->device_data;
-	return snd_seq_device_free(dev);
+	driver_unregister(&drv->driver);
 }
-
-/*
- * register the device
- */
-static int snd_seq_device_dev_register(struct snd_device *device)
-{
-	struct snd_seq_device *dev = device->device_data;
-	struct ops_list *ops;
-
-	ops = find_driver(dev->id, 0);
-	if (ops == NULL)
-		return -ENOENT;
-
-	/* initialize this device if the corresponding driver was
-	 * already loaded
-	 */
-	if (ops->driver & DRIVER_LOADED)
-		init_device(dev, ops);
-
-	unlock_driver(ops);
-	return 0;
-}
-
-/*
- * disconnect the device
- */
-static int snd_seq_device_dev_disconnect(struct snd_device *device)
-{
-	struct snd_seq_device *dev = device->device_data;
-	struct ops_list *ops;
-
-	ops = find_driver(dev->id, 0);
-	if (ops == NULL)
-		return -ENOENT;
-
-	free_device(dev, ops);
-
-	unlock_driver(ops);
-	return 0;
-}
-
-/*
- * register device driver
- * id = driver id
- * entry = driver operators - duplicated to each instance
- */
-int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
-				   int argsize)
-{
-	struct ops_list *ops;
-	struct snd_seq_device *dev;
-
-	if (id == NULL || entry == NULL ||
-	    entry->init_device == NULL || entry->free_device == NULL)
-		return -EINVAL;
-
-	ops = find_driver(id, 1);
-	if (ops == NULL)
-		return -ENOMEM;
-	if (ops->driver & DRIVER_LOADED) {
-		pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
-		unlock_driver(ops);
-		return -EBUSY;
-	}
-
-	mutex_lock(&ops->reg_mutex);
-	/* copy driver operators */
-	ops->ops = *entry;
-	ops->driver |= DRIVER_LOADED;
-	ops->argsize = argsize;
-
-	/* initialize existing devices if necessary */
-	list_for_each_entry(dev, &ops->dev_list, list) {
-		init_device(dev, ops);
-	}
-	mutex_unlock(&ops->reg_mutex);
-
-	unlock_driver(ops);
-
-	return 0;
-}
-
-
-/*
- * create driver record
- */
-static struct ops_list * create_driver(char *id)
-{
-	struct ops_list *ops;
-
-	ops = kzalloc(sizeof(*ops), GFP_KERNEL);
-	if (ops == NULL)
-		return ops;
-
-	/* set up driver entry */
-	strlcpy(ops->id, id, sizeof(ops->id));
-	mutex_init(&ops->reg_mutex);
-	/*
-	 * The ->reg_mutex locking rules are per-driver, so we create
-	 * separate per-driver lock classes:
-	 */
-	lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
-
-	ops->driver = DRIVER_EMPTY;
-	INIT_LIST_HEAD(&ops->dev_list);
-	/* lock this instance */
-	ops->used = 1;
-
-	/* register driver entry */
-	mutex_lock(&ops_mutex);
-	list_add_tail(&ops->list, &opslist);
-	num_ops++;
-	mutex_unlock(&ops_mutex);
-
-	return ops;
-}
-
-
-/*
- * unregister the specified driver
- */
-int snd_seq_device_unregister_driver(char *id)
-{
-	struct ops_list *ops;
-	struct snd_seq_device *dev;
-
-	ops = find_driver(id, 0);
-	if (ops == NULL)
-		return -ENXIO;
-	if (! (ops->driver & DRIVER_LOADED) ||
-	    (ops->driver & DRIVER_LOCKED)) {
-		pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
-			   id, ops->driver);
-		unlock_driver(ops);
-		return -EBUSY;
-	}
-
-	/* close and release all devices associated with this driver */
-	mutex_lock(&ops->reg_mutex);
-	ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
-	list_for_each_entry(dev, &ops->dev_list, list) {
-		free_device(dev, ops);
-	}
-
-	ops->driver = 0;
-	if (ops->num_init_devices > 0)
-		pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
-			   ops->num_init_devices);
-	mutex_unlock(&ops->reg_mutex);
-
-	unlock_driver(ops);
-
-	/* remove empty driver entries */
-	remove_drivers();
-
-	return 0;
-}
-
-
-/*
- * remove empty driver entries
- */
-static void remove_drivers(void)
-{
-	struct list_head *head;
-
-	mutex_lock(&ops_mutex);
-	head = opslist.next;
-	while (head != &opslist) {
-		struct ops_list *ops = list_entry(head, struct ops_list, list);
-		if (! (ops->driver & DRIVER_LOADED) &&
-		    ops->used == 0 && ops->num_devices == 0) {
-			head = head->next;
-			list_del(&ops->list);
-			kfree(ops);
-			num_ops--;
-		} else
-			head = head->next;
-	}
-	mutex_unlock(&ops_mutex);
-}
-
-/*
- * initialize the device - call init_device operator
- */
-static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
-{
-	if (! (ops->driver & DRIVER_LOADED))
-		return 0; /* driver is not loaded yet */
-	if (dev->status != SNDRV_SEQ_DEVICE_FREE)
-		return 0; /* already initialized */
-	if (ops->argsize != dev->argsize) {
-		pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
-			   dev->name, ops->id, ops->argsize, dev->argsize);
-		return -EINVAL;
-	}
-	if (ops->ops.init_device(dev) >= 0) {
-		dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
-		ops->num_init_devices++;
-	} else {
-		pr_err("ALSA: seq: init_device failed: %s: %s\n",
-			   dev->name, dev->id);
-	}
-
-	return 0;
-}
-
-/*
- * release the device - call free_device operator
- */
-static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
-{
-	int result;
-
-	if (! (ops->driver & DRIVER_LOADED))
-		return 0; /* driver is not loaded yet */
-	if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
-		return 0; /* not registered */
-	if (ops->argsize != dev->argsize) {
-		pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
-			   dev->name, ops->id, ops->argsize, dev->argsize);
-		return -EINVAL;
-	}
-	if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
-		dev->status = SNDRV_SEQ_DEVICE_FREE;
-		dev->driver_data = NULL;
-		ops->num_init_devices--;
-	} else {
-		pr_err("ALSA: seq: free_device failed: %s: %s\n",
-			   dev->name, dev->id);
-	}
-
-	return 0;
-}
-
-/*
- * find the matching driver with given id
- */
-static struct ops_list * find_driver(char *id, int create_if_empty)
-{
-	struct ops_list *ops;
-
-	mutex_lock(&ops_mutex);
-	list_for_each_entry(ops, &opslist, list) {
-		if (strcmp(ops->id, id) == 0) {
-			ops->used++;
-			mutex_unlock(&ops_mutex);
-			return ops;
-		}
-	}
-	mutex_unlock(&ops_mutex);
-	if (create_if_empty)
-		return create_driver(id);
-	return NULL;
-}
-
-static void unlock_driver(struct ops_list *ops)
-{
-	mutex_lock(&ops_mutex);
-	ops->used--;
-	mutex_unlock(&ops_mutex);
-}
-
+EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
 
 /*
  * module part
  */
 
-static int __init alsa_seq_device_init(void)
+static int __init seq_dev_proc_init(void)
 {
 #ifdef CONFIG_PROC_FS
 	info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
@@ -589,28 +287,29 @@
 	return 0;
 }
 
+static int __init alsa_seq_device_init(void)
+{
+	int err;
+
+	err = bus_register(&snd_seq_bus_type);
+	if (err < 0)
+		return err;
+	err = seq_dev_proc_init();
+	if (err < 0)
+		bus_unregister(&snd_seq_bus_type);
+	return err;
+}
+
 static void __exit alsa_seq_device_exit(void)
 {
 #ifdef CONFIG_MODULES
 	cancel_work_sync(&autoload_work);
 #endif
-	remove_drivers();
 #ifdef CONFIG_PROC_FS
 	snd_info_free_entry(info_entry);
 #endif
-	if (num_ops)
-		pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
+	bus_unregister(&snd_seq_bus_type);
 }
 
-module_init(alsa_seq_device_init)
+subsys_initcall(alsa_seq_device_init)
 module_exit(alsa_seq_device_exit)
-
-EXPORT_SYMBOL(snd_seq_device_load_drivers);
-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_init);
-EXPORT_SYMBOL(snd_seq_autoload_lock);
-EXPORT_SYMBOL(snd_seq_autoload_unlock);
-#endif
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index 5d905d9..d3a2ec4 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -214,11 +214,7 @@
 
 static int __init alsa_seq_dummy_init(void)
 {
-	int err;
-	snd_seq_autoload_lock();
-	err = register_client();
-	snd_seq_autoload_unlock();
-	return err;
+	return register_client();
 }
 
 static void __exit alsa_seq_dummy_exit(void)
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 53a403e..1d5acbe 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -33,10 +33,8 @@
 	struct snd_seq_fifo *f;
 
 	f = kzalloc(sizeof(*f), GFP_KERNEL);
-	if (f == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n");
+	if (!f)
 		return NULL;
-	}
 
 	f->pool = snd_seq_pool_new(poolsize);
 	if (f->pool == NULL) {
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index ba8e4a6..8010766 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -387,10 +387,8 @@
 		return 0;
 
 	pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
-	if (pool->ptr == NULL) {
-		pr_debug("ALSA: seq: malloc for sequencer events failed\n");
+	if (!pool->ptr)
 		return -ENOMEM;
-	}
 
 	/* add new cells to the free cell list */
 	spin_lock_irqsave(&pool->lock, flags);
@@ -463,10 +461,8 @@
 
 	/* create pool block */
 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-	if (pool == NULL) {
-		pr_debug("ALSA: seq: malloc failed for pool\n");
+	if (!pool)
 		return NULL;
-	}
 	spin_lock_init(&pool->lock);
 	pool->ptr = NULL;
 	pool->free = NULL;
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 68fec77..5dd0ee2 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -273,8 +273,9 @@
 
 /* register new midi synth port */
 static int
-snd_seq_midisynth_register_port(struct snd_seq_device *dev)
+snd_seq_midisynth_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct seq_midisynth_client *client;
 	struct seq_midisynth *msynth, *ms;
 	struct snd_seq_port_info *port;
@@ -427,8 +428,9 @@
 
 /* release midi synth port */
 static int
-snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
+snd_seq_midisynth_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct seq_midisynth_client *client;
 	struct seq_midisynth *msynth;
 	struct snd_card *card = dev->card;
@@ -457,24 +459,14 @@
 	return 0;
 }
 
+static struct snd_seq_driver seq_midisynth_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_seq_midisynth_probe,
+		.remove = snd_seq_midisynth_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_MIDISYNTH,
+	.argsize = 0,
+};
 
-static int __init alsa_seq_midi_init(void)
-{
-	static struct snd_seq_dev_ops ops = {
-		snd_seq_midisynth_register_port,
-		snd_seq_midisynth_unregister_port,
-	};
-	memset(&synths, 0, sizeof(synths));
-	snd_seq_autoload_lock();
-	snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0);
-	snd_seq_autoload_unlock();
-	return 0;
-}
-
-static void __exit alsa_seq_midi_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH);
-}
-
-module_init(alsa_seq_midi_init)
-module_exit(alsa_seq_midi_exit)
+module_snd_seq_driver(seq_midisynth_driver);
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 46ff593..55170a2 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -141,10 +141,8 @@
 
 	/* create a new port */
 	new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
-	if (! new_port) {
-		pr_debug("ALSA: seq: malloc failed for registering client port\n");
+	if (!new_port)
 		return NULL;	/* failure, out of memory */
-	}
 	/* init port data */
 	new_port->addr.client = client->number;
 	new_port->addr.port = -1;
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 021b02b..bc1c848 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -59,10 +59,8 @@
 	struct snd_seq_prioq *f;
 
 	f = kzalloc(sizeof(*f), GFP_KERNEL);
-	if (f == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n");
+	if (!f)
 		return NULL;
-	}
 	
 	spin_lock_init(&f->lock);
 	f->head = NULL;
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index aad4878..a0cda38 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -111,10 +111,8 @@
 	struct snd_seq_queue *q;
 
 	q = kzalloc(sizeof(*q), GFP_KERNEL);
-	if (q == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n");
+	if (!q)
 		return NULL;
-	}
 
 	spin_lock_init(&q->owner_lock);
 	spin_lock_init(&q->check_lock);
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index e736053..186f161 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -56,10 +56,8 @@
 	struct snd_seq_timer *tmr;
 	
 	tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
-	if (tmr == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n");
+	if (!tmr)
 		return NULL;
-	}
 	spin_lock_init(&tmr->lock);
 
 	/* reset setup to defaults */
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 185cec0..5fc93d0 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -186,7 +186,7 @@
 };
 
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-static int snd_find_free_minor(int type)
+static int snd_find_free_minor(int type, struct snd_card *card, int dev)
 {
 	int minor;
 
@@ -209,7 +209,7 @@
 	return -EBUSY;
 }
 #else
-static int snd_kernel_minor(int type, struct snd_card *card, int dev)
+static int snd_find_free_minor(int type, struct snd_card *card, int dev)
 {
 	int minor;
 
@@ -237,6 +237,8 @@
 	}
 	if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
 		return -EINVAL;
+	if (snd_minors[minor])
+		return -EBUSY;
 	return minor;
 }
 #endif
@@ -276,13 +278,7 @@
 	preg->private_data = private_data;
 	preg->card_ptr = card;
 	mutex_lock(&sound_mutex);
-#ifdef CONFIG_SND_DYNAMIC_MINORS
-	minor = snd_find_free_minor(type);
-#else
-	minor = snd_kernel_minor(type, card, dev);
-	if (minor >= 0 && snd_minors[minor])
-		minor = -EBUSY;
-#endif
+	minor = snd_find_free_minor(type, card, dev);
 	if (minor < 0) {
 		err = minor;
 		goto error;
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 490b489..a9a1a04 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -774,10 +774,8 @@
 	if (rtimer)
 		*rtimer = NULL;
 	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
-	if (timer == NULL) {
-		pr_err("ALSA: timer: cannot allocate\n");
+	if (!timer)
 		return -ENOMEM;
-	}
 	timer->tmr_class = tid->dev_class;
 	timer->card = card;
 	timer->tmr_device = tid->device;
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index a9f618e..fdae5d7 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -216,8 +216,9 @@
 
 /* ------------------------------ */
 
-static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
+static int snd_opl3_seq_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl3 *opl3;
 	int client, err;
 	char name[32];
@@ -257,8 +258,9 @@
 	return 0;
 }
 
-static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
+static int snd_opl3_seq_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl3 *opl3;
 
 	opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
@@ -275,22 +277,14 @@
 	return 0;
 }
 
-static int __init alsa_opl3_seq_init(void)
-{
-	static struct snd_seq_dev_ops ops =
-	{
-		snd_opl3_seq_new_device,
-		snd_opl3_seq_delete_device
-	};
+static struct snd_seq_driver opl3_seq_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_opl3_seq_probe,
+		.remove = snd_opl3_seq_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_OPL3,
+	.argsize = sizeof(struct snd_opl3 *),
+};
 
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops,
-					      sizeof(struct snd_opl3 *));
-}
-
-static void __exit alsa_opl3_seq_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3);
-}
-
-module_init(alsa_opl3_seq_init)
-module_exit(alsa_opl3_seq_exit)
+module_snd_seq_driver(opl3_seq_driver);
diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c
index 9919769..03d6202 100644
--- a/sound/drivers/opl4/opl4_seq.c
+++ b/sound/drivers/opl4/opl4_seq.c
@@ -124,8 +124,9 @@
 	snd_midi_channel_free_set(opl4->chset);
 }
 
-static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
+static int snd_opl4_seq_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl4 *opl4;
 	int client;
 	struct snd_seq_port_callback pcallbacks;
@@ -180,8 +181,9 @@
 	return 0;
 }
 
-static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
+static int snd_opl4_seq_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl4 *opl4;
 
 	opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
@@ -195,21 +197,14 @@
 	return 0;
 }
 
-static int __init alsa_opl4_synth_init(void)
-{
-	static struct snd_seq_dev_ops ops = {
-		snd_opl4_seq_new_device,
-		snd_opl4_seq_delete_device
-	};
+static struct snd_seq_driver opl4_seq_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_opl4_seq_probe,
+		.remove = snd_opl4_seq_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_OPL4,
+	.argsize = sizeof(struct snd_opl4 *),
+};
 
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops,
-					      sizeof(struct snd_opl4 *));
-}
-
-static void __exit alsa_opl4_synth_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4);
-}
-
-module_init(alsa_opl4_synth_init)
-module_exit(alsa_opl4_synth_exit)
+module_snd_seq_driver(opl4_seq_driver);
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 5cc356d..e061355 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -166,10 +166,10 @@
 	 * One AMDTP packet can include some frames. In blocking mode, the
 	 * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
 	 * depending on its sampling rate. For accurate period interrupt, it's
-	 * preferrable to aligh period/buffer sizes to current SYT_INTERVAL.
+	 * preferrable to align period/buffer sizes to current SYT_INTERVAL.
 	 *
-	 * TODO: These constraints can be improved with propper rules.
-	 * Currently apply LCM of SYT_INTEVALs.
+	 * TODO: These constraints can be improved with proper rules.
+	 * Currently apply LCM of SYT_INTERVALs.
 	 */
 	err = snd_pcm_hw_constraint_step(runtime, 0,
 					 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
@@ -270,7 +270,7 @@
  * @s: the AMDTP stream to configure
  * @format: the format of the ALSA PCM device
  *
- * The sample format must be set after the other paramters (rate/PCM channels/
+ * The sample format must be set after the other parameters (rate/PCM channels/
  * MIDI) and before the stream is started, and must not be changed while the
  * stream is running.
  */
diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c
index a422aaa..9ee25a6 100644
--- a/sound/firewire/bebob/bebob_maudio.c
+++ b/sound/firewire/bebob/bebob_maudio.c
@@ -96,10 +96,10 @@
 	struct fw_device *device = fw_parent_device(unit);
 	int err, rcode;
 	u64 date;
-	__be32 cues[3] = {
-		MAUDIO_BOOTLOADER_CUE1,
-		MAUDIO_BOOTLOADER_CUE2,
-		MAUDIO_BOOTLOADER_CUE3
+	__le32 cues[3] = {
+		cpu_to_le32(MAUDIO_BOOTLOADER_CUE1),
+		cpu_to_le32(MAUDIO_BOOTLOADER_CUE2),
+		cpu_to_le32(MAUDIO_BOOTLOADER_CUE3)
 	};
 
 	/* check date of software used to build */
diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c
index 2a85e42..f550808 100644
--- a/sound/firewire/fireworks/fireworks_transaction.c
+++ b/sound/firewire/fireworks/fireworks_transaction.c
@@ -13,7 +13,7 @@
  *
  * Transaction substance:
  *  At first, 6 data exist. Following to the data, parameters for each command
- *  exist. All of the parameters are 32 bit alighed to big endian.
+ *  exist. All of the parameters are 32 bit aligned to big endian.
  *   data[0]:	Length of transaction substance
  *   data[1]:	Transaction version
  *   data[2]:	Sequence number. This is incremented by the device
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
new file mode 100644
index 0000000..001c658
--- /dev/null
+++ b/sound/hda/Kconfig
@@ -0,0 +1,3 @@
+config SND_HDA_CORE
+	tristate
+	select REGMAP
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
new file mode 100644
index 0000000..7a359f5
--- /dev/null
+++ b/sound/hda/Makefile
@@ -0,0 +1,7 @@
+snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
+	hdac_regmap.o array.o
+
+snd-hda-core-objs += trace.o
+CFLAGS_trace.o := -I$(src)
+
+obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
diff --git a/sound/hda/array.c b/sound/hda/array.c
new file mode 100644
index 0000000..516795b
--- /dev/null
+++ b/sound/hda/array.c
@@ -0,0 +1,49 @@
+/*
+ * generic arrays
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+
+/**
+ * snd_array_new - get a new element from the given array
+ * @array: the array object
+ *
+ * Get a new element from the given array.  If it exceeds the
+ * pre-allocated array size, re-allocate the array.
+ *
+ * Returns NULL if allocation failed.
+ */
+void *snd_array_new(struct snd_array *array)
+{
+	if (snd_BUG_ON(!array->elem_size))
+		return NULL;
+	if (array->used >= array->alloced) {
+		int num = array->alloced + array->alloc_align;
+		int size = (num + 1) * array->elem_size;
+		void *nlist;
+		if (snd_BUG_ON(num >= 4096))
+			return NULL;
+		nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
+		if (!nlist)
+			return NULL;
+		array->list = nlist;
+		array->alloced = num;
+	}
+	return snd_array_elem(array, array->used++);
+}
+EXPORT_SYMBOL_GPL(snd_array_new);
+
+/**
+ * snd_array_free - free the given array elements
+ * @array: the array object
+ */
+void snd_array_free(struct snd_array *array)
+{
+	kfree(array->list);
+	array->used = 0;
+	array->alloced = 0;
+	array->list = NULL;
+}
+EXPORT_SYMBOL_GPL(snd_array_free);
diff --git a/sound/hda/hda_bus_type.c b/sound/hda/hda_bus_type.c
new file mode 100644
index 0000000..519914a
--- /dev/null
+++ b/sound/hda/hda_bus_type.c
@@ -0,0 +1,42 @@
+/*
+ * HD-audio bus
+ */
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <sound/hdaudio.h>
+
+MODULE_DESCRIPTION("HD-audio bus");
+MODULE_LICENSE("GPL");
+
+static int hda_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct hdac_device *hdev = dev_to_hdac_dev(dev);
+	struct hdac_driver *hdrv = drv_to_hdac_driver(drv);
+
+	if (hdev->type != hdrv->type)
+		return 0;
+	if (hdrv->match)
+		return hdrv->match(hdev, hdrv);
+	return 1;
+}
+
+struct bus_type snd_hda_bus_type = {
+	.name = "hdaudio",
+	.match = hda_bus_match,
+};
+EXPORT_SYMBOL_GPL(snd_hda_bus_type);
+
+static int __init hda_bus_init(void)
+{
+	return bus_register(&snd_hda_bus_type);
+}
+
+static void __exit hda_bus_exit(void)
+{
+	bus_unregister(&snd_hda_bus_type);
+}
+
+subsys_initcall(hda_bus_init);
+module_exit(hda_bus_exit);
diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c
new file mode 100644
index 0000000..8e262da
--- /dev/null
+++ b/sound/hda/hdac_bus.c
@@ -0,0 +1,186 @@
+/*
+ * HD-audio core bus driver
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <sound/hdaudio.h>
+#include "trace.h"
+
+static void process_unsol_events(struct work_struct *work);
+
+/**
+ * snd_hdac_bus_init - initialize a HD-audio bas bus
+ * @bus: the pointer to bus object
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
+		      const struct hdac_bus_ops *ops)
+{
+	memset(bus, 0, sizeof(*bus));
+	bus->dev = dev;
+	bus->ops = ops;
+	INIT_LIST_HEAD(&bus->codec_list);
+	INIT_WORK(&bus->unsol_work, process_unsol_events);
+	mutex_init(&bus->cmd_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_init);
+
+/**
+ * snd_hdac_bus_exit - clean up a HD-audio bas bus
+ * @bus: the pointer to bus object
+ */
+void snd_hdac_bus_exit(struct hdac_bus *bus)
+{
+	WARN_ON(!list_empty(&bus->codec_list));
+	cancel_work_sync(&bus->unsol_work);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_exit);
+
+/**
+ * snd_hdac_bus_exec_verb - execute a HD-audio verb on the given bus
+ * @bus: bus object
+ * @cmd: HD-audio encoded verb
+ * @res: pointer to store the response, NULL if performing asynchronously
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
+			   unsigned int cmd, unsigned int *res)
+{
+	int err;
+
+	mutex_lock(&bus->cmd_mutex);
+	err = snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res);
+	mutex_unlock(&bus->cmd_mutex);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb);
+
+/**
+ * snd_hdac_bus_exec_verb_unlocked - unlocked version
+ * @bus: bus object
+ * @cmd: HD-audio encoded verb
+ * @res: pointer to store the response, NULL if performing asynchronously
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
+				    unsigned int cmd, unsigned int *res)
+{
+	unsigned int tmp;
+	int err;
+
+	if (cmd == ~0)
+		return -EINVAL;
+
+	if (res)
+		*res = -1;
+	else if (bus->sync_write)
+		res = &tmp;
+	for (;;) {
+		trace_hda_send_cmd(bus, cmd);
+		err = bus->ops->command(bus, cmd);
+		if (err != -EAGAIN)
+			break;
+		/* process pending verbs */
+		err = bus->ops->get_response(bus, addr, &tmp);
+		if (err)
+			break;
+	}
+	if (!err && res) {
+		err = bus->ops->get_response(bus, addr, res);
+		trace_hda_get_response(bus, addr, *res);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb_unlocked);
+
+/**
+ * snd_hdac_bus_queue_event - add an unsolicited event to queue
+ * @bus: the BUS
+ * @res: unsolicited event (lower 32bit of RIRB entry)
+ * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
+ *
+ * Adds the given event to the queue.  The events are processed in
+ * the workqueue asynchronously.  Call this function in the interrupt
+ * hanlder when RIRB receives an unsolicited event.
+ */
+void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex)
+{
+	unsigned int wp;
+
+	if (!bus)
+		return;
+
+	trace_hda_unsol_event(bus, res, res_ex);
+	wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE;
+	bus->unsol_wp = wp;
+
+	wp <<= 1;
+	bus->unsol_queue[wp] = res;
+	bus->unsol_queue[wp + 1] = res_ex;
+
+	schedule_work(&bus->unsol_work);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event);
+
+/*
+ * process queued unsolicited events
+ */
+static void process_unsol_events(struct work_struct *work)
+{
+	struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work);
+	struct hdac_device *codec;
+	struct hdac_driver *drv;
+	unsigned int rp, caddr, res;
+
+	while (bus->unsol_rp != bus->unsol_wp) {
+		rp = (bus->unsol_rp + 1) % HDA_UNSOL_QUEUE_SIZE;
+		bus->unsol_rp = rp;
+		rp <<= 1;
+		res = bus->unsol_queue[rp];
+		caddr = bus->unsol_queue[rp + 1];
+		if (!(caddr & (1 << 4))) /* no unsolicited event? */
+			continue;
+		codec = bus->caddr_tbl[caddr & 0x0f];
+		if (!codec || !codec->dev.driver)
+			continue;
+		drv = drv_to_hdac_driver(codec->dev.driver);
+		if (drv->unsol_event)
+			drv->unsol_event(codec, res);
+	}
+}
+
+int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec)
+{
+	if (bus->caddr_tbl[codec->addr]) {
+		dev_err(bus->dev, "address 0x%x is already occupied\n",
+			codec->addr);
+		return -EBUSY;
+	}
+
+	list_add_tail(&codec->list, &bus->codec_list);
+	bus->caddr_tbl[codec->addr] = codec;
+	set_bit(codec->addr, &bus->codec_powered);
+	bus->num_codecs++;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device);
+
+void snd_hdac_bus_remove_device(struct hdac_bus *bus,
+				struct hdac_device *codec)
+{
+	WARN_ON(bus != codec->bus);
+	if (list_empty(&codec->list))
+		return;
+	list_del_init(&codec->list);
+	bus->caddr_tbl[codec->addr] = NULL;
+	clear_bit(codec->addr, &bus->codec_powered);
+	bus->num_codecs--;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device);
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
new file mode 100644
index 0000000..f75bf56
--- /dev/null
+++ b/sound/hda/hdac_device.c
@@ -0,0 +1,599 @@
+/*
+ * HD-audio codec core device
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/pm_runtime.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_regmap.h>
+#include "local.h"
+
+static void setup_fg_nodes(struct hdac_device *codec);
+static int get_codec_vendor_name(struct hdac_device *codec);
+
+static void default_release(struct device *dev)
+{
+	snd_hdac_device_exit(container_of(dev, struct hdac_device, dev));
+}
+
+/**
+ * snd_hdac_device_init - initialize the HD-audio codec base device
+ * @codec: device to initialize
+ * @bus: but to attach
+ * @name: device name string
+ * @addr: codec address
+ *
+ * Returns zero for success or a negative error code.
+ *
+ * This function increments the runtime PM counter and marks it active.
+ * The caller needs to turn it off appropriately later.
+ *
+ * The caller needs to set the device's release op properly by itself.
+ */
+int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
+			 const char *name, unsigned int addr)
+{
+	struct device *dev;
+	hda_nid_t fg;
+	int err;
+
+	dev = &codec->dev;
+	device_initialize(dev);
+	dev->parent = bus->dev;
+	dev->bus = &snd_hda_bus_type;
+	dev->release = default_release;
+	dev->groups = hdac_dev_attr_groups;
+	dev_set_name(dev, "%s", name);
+	device_enable_async_suspend(dev);
+
+	codec->bus = bus;
+	codec->addr = addr;
+	codec->type = HDA_DEV_CORE;
+	pm_runtime_set_active(&codec->dev);
+	pm_runtime_get_noresume(&codec->dev);
+	atomic_set(&codec->in_pm, 0);
+
+	err = snd_hdac_bus_add_device(bus, codec);
+	if (err < 0)
+		goto error;
+
+	/* fill parameters */
+	codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+					      AC_PAR_VENDOR_ID);
+	if (codec->vendor_id == -1) {
+		/* read again, hopefully the access method was corrected
+		 * in the last read...
+		 */
+		codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+						      AC_PAR_VENDOR_ID);
+	}
+
+	codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+						 AC_PAR_SUBSYSTEM_ID);
+	codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+						AC_PAR_REV_ID);
+
+	setup_fg_nodes(codec);
+	if (!codec->afg && !codec->mfg) {
+		dev_err(dev, "no AFG or MFG node found\n");
+		err = -ENODEV;
+		goto error;
+	}
+
+	fg = codec->afg ? codec->afg : codec->mfg;
+
+	err = snd_hdac_refresh_widgets(codec);
+	if (err < 0)
+		goto error;
+
+	codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE);
+	/* reread ssid if not set by parameter */
+	if (codec->subsystem_id == -1 || codec->subsystem_id == 0)
+		snd_hdac_read(codec, fg, AC_VERB_GET_SUBSYSTEM_ID, 0,
+			      &codec->subsystem_id);
+
+	err = get_codec_vendor_name(codec);
+	if (err < 0)
+		goto error;
+
+	codec->chip_name = kasprintf(GFP_KERNEL, "ID %x",
+				     codec->vendor_id & 0xffff);
+	if (!codec->chip_name) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	return 0;
+
+ error:
+	put_device(&codec->dev);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_init);
+
+/**
+ * snd_hdac_device_exit - clean up the HD-audio codec base device
+ * @codec: device to clean up
+ */
+void snd_hdac_device_exit(struct hdac_device *codec)
+{
+	pm_runtime_put_noidle(&codec->dev);
+	snd_hdac_bus_remove_device(codec->bus, codec);
+	kfree(codec->vendor_name);
+	kfree(codec->chip_name);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_exit);
+
+/**
+ * snd_hdac_device_register - register the hd-audio codec base device
+ * codec: the device to register
+ */
+int snd_hdac_device_register(struct hdac_device *codec)
+{
+	int err;
+
+	err = device_add(&codec->dev);
+	if (err < 0)
+		return err;
+	err = hda_widget_sysfs_init(codec);
+	if (err < 0) {
+		device_del(&codec->dev);
+		return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_register);
+
+/**
+ * snd_hdac_device_unregister - unregister the hd-audio codec base device
+ * codec: the device to unregister
+ */
+void snd_hdac_device_unregister(struct hdac_device *codec)
+{
+	if (device_is_registered(&codec->dev)) {
+		hda_widget_sysfs_exit(codec);
+		device_del(&codec->dev);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_unregister);
+
+/**
+ * snd_hdac_make_cmd - compose a 32bit command word to be sent to the
+ *	HD-audio controller
+ * @codec: the codec object
+ * @nid: NID to encode
+ * @verb: verb to encode
+ * @parm: parameter to encode
+ *
+ * Return an encoded command verb or -1 for error.
+ */
+unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
+			       unsigned int verb, unsigned int parm)
+{
+	u32 val, addr;
+
+	addr = codec->addr;
+	if ((addr & ~0xf) || (nid & ~0x7f) ||
+	    (verb & ~0xfff) || (parm & ~0xffff)) {
+		dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n",
+			addr, nid, verb, parm);
+		return -1;
+	}
+
+	val = addr << 28;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= parm;
+	return val;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_make_cmd);
+
+/**
+ * snd_hdac_exec_verb - execute an encoded verb
+ * @codec: the codec object
+ * @cmd: encoded verb to execute
+ * @flags: optional flags, pass zero for default
+ * @res: the pointer to store the result, NULL if running async
+ *
+ * Returns zero if successful, or a negative error code.
+ *
+ * This calls the exec_verb op when set in hdac_codec.  If not,
+ * call the default snd_hdac_bus_exec_verb().
+ */
+int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
+		       unsigned int flags, unsigned int *res)
+{
+	if (codec->exec_verb)
+		return codec->exec_verb(codec, cmd, flags, res);
+	return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_exec_verb);
+
+
+/**
+ * snd_hdac_read - execute a verb
+ * @codec: the codec object
+ * @nid: NID to execute a verb
+ * @verb: verb to execute
+ * @parm: parameter for a verb
+ * @res: the pointer to store the result, NULL if running async
+ *
+ * Returns zero if successful, or a negative error code.
+ */
+int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
+		  unsigned int verb, unsigned int parm, unsigned int *res)
+{
+	unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm);
+
+	return snd_hdac_exec_verb(codec, cmd, 0, res);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_read);
+
+/**
+ * _snd_hdac_read_parm - read a parmeter
+ *
+ * This function returns zero or an error unlike snd_hdac_read_parm().
+ */
+int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
+			unsigned int *res)
+{
+	unsigned int cmd;
+
+	cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm;
+	return snd_hdac_regmap_read_raw(codec, cmd, res);
+}
+EXPORT_SYMBOL_GPL(_snd_hdac_read_parm);
+
+/**
+ * snd_hdac_read_parm_uncached - read a codec parameter without caching
+ * @codec: the codec object
+ * @nid: NID to read a parameter
+ * @parm: parameter to read
+ *
+ * Returns -1 for error.  If you need to distinguish the error more
+ * strictly, use snd_hdac_read() directly.
+ */
+int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
+				int parm)
+{
+	int val;
+
+	if (codec->regmap)
+		regcache_cache_bypass(codec->regmap, true);
+	val = snd_hdac_read_parm(codec, nid, parm);
+	if (codec->regmap)
+		regcache_cache_bypass(codec->regmap, false);
+	return val;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached);
+
+/**
+ * snd_hdac_override_parm - override read-only parameters
+ * @codec: the codec object
+ * @nid: NID for the parameter
+ * @parm: the parameter to change
+ * @val: the parameter value to overwrite
+ */
+int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
+			   unsigned int parm, unsigned int val)
+{
+	unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm;
+	int err;
+
+	if (!codec->regmap)
+		return -EINVAL;
+
+	codec->caps_overwriting = true;
+	err = snd_hdac_regmap_write_raw(codec, verb, val);
+	codec->caps_overwriting = false;
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_override_parm);
+
+/**
+ * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes
+ * @codec: the codec object
+ * @nid: NID to inspect
+ * @start_id: the pointer to store the starting NID
+ *
+ * Returns the number of subtree nodes or zero if not found.
+ * This function reads parameters always without caching.
+ */
+int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
+			   hda_nid_t *start_id)
+{
+	unsigned int parm;
+
+	parm = snd_hdac_read_parm_uncached(codec, nid, AC_PAR_NODE_COUNT);
+	if (parm == -1) {
+		*start_id = 0;
+		return 0;
+	}
+	*start_id = (parm >> 16) & 0x7fff;
+	return (int)(parm & 0x7fff);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes);
+
+/*
+ * look for an AFG and MFG nodes
+ */
+static void setup_fg_nodes(struct hdac_device *codec)
+{
+	int i, total_nodes, function_id;
+	hda_nid_t nid;
+
+	total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
+	for (i = 0; i < total_nodes; i++, nid++) {
+		function_id = snd_hdac_read_parm(codec, nid,
+						 AC_PAR_FUNCTION_TYPE);
+		switch (function_id & 0xff) {
+		case AC_GRP_AUDIO_FUNCTION:
+			codec->afg = nid;
+			codec->afg_function_id = function_id & 0xff;
+			codec->afg_unsol = (function_id >> 8) & 1;
+			break;
+		case AC_GRP_MODEM_FUNCTION:
+			codec->mfg = nid;
+			codec->mfg_function_id = function_id & 0xff;
+			codec->mfg_unsol = (function_id >> 8) & 1;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ * snd_hdac_refresh_widgets - Reset the widget start/end nodes
+ * @codec: the codec object
+ */
+int snd_hdac_refresh_widgets(struct hdac_device *codec)
+{
+	hda_nid_t start_nid;
+	int nums;
+
+	nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
+	if (!start_nid || nums <= 0 || nums >= 0xff) {
+		dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n",
+			codec->afg);
+		return -EINVAL;
+	}
+
+	codec->num_nodes = nums;
+	codec->start_nid = start_nid;
+	codec->end_nid = start_nid + nums;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
+
+/* return CONNLIST_LEN parameter of the given widget */
+static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid)
+{
+	unsigned int wcaps = get_wcaps(codec, nid);
+	unsigned int parm;
+
+	if (!(wcaps & AC_WCAP_CONN_LIST) &&
+	    get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+		return 0;
+
+	parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN);
+	if (parm == -1)
+		parm = 0;
+	return parm;
+}
+
+/**
+ * snd_hdac_get_connections - get a widget connection list
+ * @codec: the codec object
+ * @nid: NID
+ * @conn_list: the array to store the results, can be NULL
+ * @max_conns: the max size of the given array
+ *
+ * Returns the number of connected widgets, zero for no connection, or a
+ * negative error code.  When the number of elements don't fit with the
+ * given array size, it returns -ENOSPC.
+ *
+ * When @conn_list is NULL, it just checks the number of connections.
+ */
+int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
+			     hda_nid_t *conn_list, int max_conns)
+{
+	unsigned int parm;
+	int i, conn_len, conns, err;
+	unsigned int shift, num_elems, mask;
+	hda_nid_t prev_nid;
+	int null_count = 0;
+
+	parm = get_num_conns(codec, nid);
+	if (!parm)
+		return 0;
+
+	if (parm & AC_CLIST_LONG) {
+		/* long form */
+		shift = 16;
+		num_elems = 2;
+	} else {
+		/* short form */
+		shift = 8;
+		num_elems = 4;
+	}
+	conn_len = parm & AC_CLIST_LENGTH;
+	mask = (1 << (shift-1)) - 1;
+
+	if (!conn_len)
+		return 0; /* no connection */
+
+	if (conn_len == 1) {
+		/* single connection */
+		err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0,
+				    &parm);
+		if (err < 0)
+			return err;
+		if (conn_list)
+			conn_list[0] = parm & mask;
+		return 1;
+	}
+
+	/* multi connection */
+	conns = 0;
+	prev_nid = 0;
+	for (i = 0; i < conn_len; i++) {
+		int range_val;
+		hda_nid_t val, n;
+
+		if (i % num_elems == 0) {
+			err = snd_hdac_read(codec, nid,
+					    AC_VERB_GET_CONNECT_LIST, i,
+					    &parm);
+			if (err < 0)
+				return -EIO;
+		}
+		range_val = !!(parm & (1 << (shift-1))); /* ranges */
+		val = parm & mask;
+		if (val == 0 && null_count++) {  /* no second chance */
+			dev_dbg(&codec->dev,
+				"invalid CONNECT_LIST verb %x[%i]:%x\n",
+				nid, i, parm);
+			return 0;
+		}
+		parm >>= shift;
+		if (range_val) {
+			/* ranges between the previous and this one */
+			if (!prev_nid || prev_nid >= val) {
+				dev_warn(&codec->dev,
+					 "invalid dep_range_val %x:%x\n",
+					 prev_nid, val);
+				continue;
+			}
+			for (n = prev_nid + 1; n <= val; n++) {
+				if (conn_list) {
+					if (conns >= max_conns)
+						return -ENOSPC;
+					conn_list[conns] = n;
+				}
+				conns++;
+			}
+		} else {
+			if (conn_list) {
+				if (conns >= max_conns)
+					return -ENOSPC;
+				conn_list[conns] = val;
+			}
+			conns++;
+		}
+		prev_nid = val;
+	}
+	return conns;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_get_connections);
+
+#ifdef CONFIG_PM
+/**
+ * snd_hdac_power_up - power up the codec
+ * @codec: the codec object
+ *
+ * This function calls the runtime PM helper to power up the given codec.
+ * Unlike snd_hdac_power_up_pm(), you should call this only for the code
+ * path that isn't included in PM path.  Otherwise it gets stuck.
+ */
+void snd_hdac_power_up(struct hdac_device *codec)
+{
+	pm_runtime_get_sync(&codec->dev);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_up);
+
+/**
+ * snd_hdac_power_down - power down the codec
+ * @codec: the codec object
+ */
+void snd_hdac_power_down(struct hdac_device *codec)
+{
+	struct device *dev = &codec->dev;
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_down);
+
+/**
+ * snd_hdac_power_up_pm - power up the codec
+ * @codec: the codec object
+ *
+ * This function can be called in a recursive code path like init code
+ * which may be called by PM suspend/resume again.  OTOH, if a power-up
+ * call must wake up the sleeper (e.g. in a kctl callback), use
+ * snd_hdac_power_up() instead.
+ */
+void snd_hdac_power_up_pm(struct hdac_device *codec)
+{
+	if (!atomic_inc_not_zero(&codec->in_pm))
+		snd_hdac_power_up(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
+
+/**
+ * snd_hdac_power_down_pm - power down the codec
+ * @codec: the codec object
+ *
+ * Like snd_hdac_power_up_pm(), this function is used in a recursive
+ * code path like init code which may be called by PM suspend/resume again.
+ */
+void snd_hdac_power_down_pm(struct hdac_device *codec)
+{
+	if (atomic_dec_if_positive(&codec->in_pm) < 0)
+		snd_hdac_power_down(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
+#endif
+
+/* codec vendor labels */
+struct hda_vendor_id {
+	unsigned int id;
+	const char *name;
+};
+
+static struct hda_vendor_id hda_vendor_ids[] = {
+	{ 0x1002, "ATI" },
+	{ 0x1013, "Cirrus Logic" },
+	{ 0x1057, "Motorola" },
+	{ 0x1095, "Silicon Image" },
+	{ 0x10de, "Nvidia" },
+	{ 0x10ec, "Realtek" },
+	{ 0x1102, "Creative" },
+	{ 0x1106, "VIA" },
+	{ 0x111d, "IDT" },
+	{ 0x11c1, "LSI" },
+	{ 0x11d4, "Analog Devices" },
+	{ 0x13f6, "C-Media" },
+	{ 0x14f1, "Conexant" },
+	{ 0x17e8, "Chrontel" },
+	{ 0x1854, "LG" },
+	{ 0x1aec, "Wolfson Microelectronics" },
+	{ 0x1af4, "QEMU" },
+	{ 0x434d, "C-Media" },
+	{ 0x8086, "Intel" },
+	{ 0x8384, "SigmaTel" },
+	{} /* terminator */
+};
+
+/* store the codec vendor name */
+static int get_codec_vendor_name(struct hdac_device *codec)
+{
+	const struct hda_vendor_id *c;
+	u16 vendor_id = codec->vendor_id >> 16;
+
+	for (c = hda_vendor_ids; c->id; c++) {
+		if (c->id == vendor_id) {
+			codec->vendor_name = kstrdup(c->name, GFP_KERNEL);
+			return codec->vendor_name ? 0 : -ENOMEM;
+		}
+	}
+
+	codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id);
+	return codec->vendor_name ? 0 : -ENOMEM;
+}
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c
new file mode 100644
index 0000000..51f1b5c
--- /dev/null
+++ b/sound/hda/hdac_regmap.c
@@ -0,0 +1,472 @@
+/*
+ * Regmap support for HD-audio verbs
+ *
+ * A virtual register is translated to one or more hda verbs for write,
+ * vice versa for read.
+ *
+ * A few limitations:
+ * - Provided for not all verbs but only subset standard non-volatile verbs.
+ * - For reading, only AC_VERB_GET_* variants can be used.
+ * - For writing, mapped to the *corresponding* AC_VERB_SET_* variants,
+ *   so can't handle asymmetric verbs for read and write
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_regmap.h>
+
+#ifdef CONFIG_PM
+#define codec_is_running(codec)				\
+	(atomic_read(&(codec)->in_pm) ||		\
+	 !pm_runtime_suspended(&(codec)->dev))
+#else
+#define codec_is_running(codec)		true
+#endif
+
+#define get_verb(reg)	(((reg) >> 8) & 0xfff)
+
+static bool hda_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct hdac_device *codec = dev_to_hdac_dev(dev);
+	unsigned int verb = get_verb(reg);
+
+	switch (verb) {
+	case AC_VERB_GET_PROC_COEF:
+		return !codec->cache_coef;
+	case AC_VERB_GET_COEF_INDEX:
+	case AC_VERB_GET_PROC_STATE:
+	case AC_VERB_GET_POWER_STATE:
+	case AC_VERB_GET_PIN_SENSE:
+	case AC_VERB_GET_HDMI_DIP_SIZE:
+	case AC_VERB_GET_HDMI_ELDD:
+	case AC_VERB_GET_HDMI_DIP_INDEX:
+	case AC_VERB_GET_HDMI_DIP_DATA:
+	case AC_VERB_GET_HDMI_DIP_XMIT:
+	case AC_VERB_GET_HDMI_CP_CTRL:
+	case AC_VERB_GET_HDMI_CHAN_SLOT:
+	case AC_VERB_GET_DEVICE_SEL:
+	case AC_VERB_GET_DEVICE_LIST:	/* read-only volatile */
+		return true;
+	}
+
+	return false;
+}
+
+static bool hda_writeable_reg(struct device *dev, unsigned int reg)
+{
+	struct hdac_device *codec = dev_to_hdac_dev(dev);
+	unsigned int verb = get_verb(reg);
+	int i;
+
+	for (i = 0; i < codec->vendor_verbs.used; i++) {
+		unsigned int *v = snd_array_elem(&codec->vendor_verbs, i);
+		if (verb == *v)
+			return true;
+	}
+
+	if (codec->caps_overwriting)
+		return true;
+
+	switch (verb & 0xf00) {
+	case AC_VERB_GET_STREAM_FORMAT:
+	case AC_VERB_GET_AMP_GAIN_MUTE:
+		return true;
+	case AC_VERB_GET_PROC_COEF:
+		return codec->cache_coef;
+	case 0xf00:
+		break;
+	default:
+		return false;
+	}
+
+	switch (verb) {
+	case AC_VERB_GET_CONNECT_SEL:
+	case AC_VERB_GET_SDI_SELECT:
+	case AC_VERB_GET_PIN_WIDGET_CONTROL:
+	case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */
+	case AC_VERB_GET_BEEP_CONTROL:
+	case AC_VERB_GET_EAPD_BTLENABLE:
+	case AC_VERB_GET_DIGI_CONVERT_1:
+	case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */
+	case AC_VERB_GET_VOLUME_KNOB_CONTROL:
+	case AC_VERB_GET_GPIO_MASK:
+	case AC_VERB_GET_GPIO_DIRECTION:
+	case AC_VERB_GET_GPIO_DATA: /* not for volatile read */
+	case AC_VERB_GET_GPIO_WAKE_MASK:
+	case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK:
+	case AC_VERB_GET_GPIO_STICKY_MASK:
+		return true;
+	}
+
+	return false;
+}
+
+static bool hda_readable_reg(struct device *dev, unsigned int reg)
+{
+	struct hdac_device *codec = dev_to_hdac_dev(dev);
+	unsigned int verb = get_verb(reg);
+
+	if (codec->caps_overwriting)
+		return true;
+
+	switch (verb) {
+	case AC_VERB_PARAMETERS:
+	case AC_VERB_GET_CONNECT_LIST:
+	case AC_VERB_GET_SUBSYSTEM_ID:
+		return true;
+	/* below are basically writable, but disabled for reducing unnecessary
+	 * writes at sync
+	 */
+	case AC_VERB_GET_CONFIG_DEFAULT: /* usually just read */
+	case AC_VERB_GET_CONV: /* managed in PCM code */
+	case AC_VERB_GET_CVT_CHAN_COUNT: /* managed in HDMI CA code */
+		return true;
+	}
+
+	return hda_writeable_reg(dev, reg);
+}
+
+/*
+ * Stereo amp pseudo register:
+ * for making easier to handle the stereo volume control, we provide a
+ * fake register to deal both left and right channels by a single
+ * (pseudo) register access.  A verb consisting of SET_AMP_GAIN with
+ * *both* SET_LEFT and SET_RIGHT bits takes a 16bit value, the lower 8bit
+ * for the left and the upper 8bit for the right channel.
+ */
+static bool is_stereo_amp_verb(unsigned int reg)
+{
+	if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE)
+		return false;
+	return (reg & (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT)) ==
+		(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
+}
+
+/* read a pseudo stereo amp register (16bit left+right) */
+static int hda_reg_read_stereo_amp(struct hdac_device *codec,
+				   unsigned int reg, unsigned int *val)
+{
+	unsigned int left, right;
+	int err;
+
+	reg &= ~(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left);
+	if (err < 0)
+		return err;
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right);
+	if (err < 0)
+		return err;
+	*val = left | (right << 8);
+	return 0;
+}
+
+/* write a pseudo stereo amp register (16bit left+right) */
+static int hda_reg_write_stereo_amp(struct hdac_device *codec,
+				    unsigned int reg, unsigned int val)
+{
+	int err;
+	unsigned int verb, left, right;
+
+	verb = AC_VERB_SET_AMP_GAIN_MUTE << 8;
+	if (reg & AC_AMP_GET_OUTPUT)
+		verb |= AC_AMP_SET_OUTPUT;
+	else
+		verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8);
+	reg = (reg & ~0xfffff) | verb;
+
+	left = val & 0xff;
+	right = (val >> 8) & 0xff;
+	if (left == right) {
+		reg |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
+		return snd_hdac_exec_verb(codec, reg | left, 0, NULL);
+	}
+
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL);
+	if (err < 0)
+		return err;
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/* read a pseudo coef register (16bit) */
+static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg,
+			     unsigned int *val)
+{
+	unsigned int verb;
+	int err;
+
+	if (!codec->cache_coef)
+		return -EINVAL;
+	/* LSB 8bit = coef index */
+	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
+	err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+	if (err < 0)
+		return err;
+	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8);
+	return snd_hdac_exec_verb(codec, verb, 0, val);
+}
+
+/* write a pseudo coef register (16bit) */
+static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg,
+			      unsigned int val)
+{
+	unsigned int verb;
+	int err;
+
+	if (!codec->cache_coef)
+		return -EINVAL;
+	/* LSB 8bit = coef index */
+	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
+	err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+	if (err < 0)
+		return err;
+	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) |
+		(val & 0xffff);
+	return snd_hdac_exec_verb(codec, verb, 0, NULL);
+}
+
+static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct hdac_device *codec = context;
+	int verb = get_verb(reg);
+	int err;
+
+	if (!codec_is_running(codec) && verb != AC_VERB_GET_POWER_STATE)
+		return -EAGAIN;
+	reg |= (codec->addr << 28);
+	if (is_stereo_amp_verb(reg))
+		return hda_reg_read_stereo_amp(codec, reg, val);
+	if (verb == AC_VERB_GET_PROC_COEF)
+		return hda_reg_read_coef(codec, reg, val);
+	err = snd_hdac_exec_verb(codec, reg, 0, val);
+	if (err < 0)
+		return err;
+	/* special handling for asymmetric reads */
+	if (verb == AC_VERB_GET_POWER_STATE) {
+		if (*val & AC_PWRST_ERROR)
+			*val = -1;
+		else /* take only the actual state */
+			*val = (*val >> 4) & 0x0f;
+	}
+	return 0;
+}
+
+static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct hdac_device *codec = context;
+	unsigned int verb;
+	int i, bytes, err;
+
+	reg &= ~0x00080000U; /* drop GET bit */
+	reg |= (codec->addr << 28);
+	verb = get_verb(reg);
+
+	if (!codec_is_running(codec) && verb != AC_VERB_SET_POWER_STATE)
+		return codec->lazy_cache ? 0 : -EAGAIN;
+
+	if (is_stereo_amp_verb(reg))
+		return hda_reg_write_stereo_amp(codec, reg, val);
+
+	if (verb == AC_VERB_SET_PROC_COEF)
+		return hda_reg_write_coef(codec, reg, val);
+
+	switch (verb & 0xf00) {
+	case AC_VERB_SET_AMP_GAIN_MUTE:
+		verb = AC_VERB_SET_AMP_GAIN_MUTE;
+		if (reg & AC_AMP_GET_LEFT)
+			verb |= AC_AMP_SET_LEFT >> 8;
+		else
+			verb |= AC_AMP_SET_RIGHT >> 8;
+		if (reg & AC_AMP_GET_OUTPUT) {
+			verb |= AC_AMP_SET_OUTPUT >> 8;
+		} else {
+			verb |= AC_AMP_SET_INPUT >> 8;
+			verb |= reg & 0xf;
+		}
+		break;
+	}
+
+	switch (verb) {
+	case AC_VERB_SET_DIGI_CONVERT_1:
+		bytes = 2;
+		break;
+	case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0:
+		bytes = 4;
+		break;
+	default:
+		bytes = 1;
+		break;
+	}
+
+	for (i = 0; i < bytes; i++) {
+		reg &= ~0xfffff;
+		reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
+		err = snd_hdac_exec_verb(codec, reg, 0, NULL);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config hda_regmap_cfg = {
+	.name = "hdaudio",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.max_register = 0xfffffff,
+	.writeable_reg = hda_writeable_reg,
+	.readable_reg = hda_readable_reg,
+	.volatile_reg = hda_volatile_reg,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_read = hda_reg_read,
+	.reg_write = hda_reg_write,
+	.use_single_rw = true,
+};
+
+int snd_hdac_regmap_init(struct hdac_device *codec)
+{
+	struct regmap *regmap;
+
+	regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+	codec->regmap = regmap;
+	snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
+
+void snd_hdac_regmap_exit(struct hdac_device *codec)
+{
+	if (codec->regmap) {
+		regmap_exit(codec->regmap);
+		codec->regmap = NULL;
+		snd_array_free(&codec->vendor_verbs);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);
+
+/**
+ * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
+ * @codec: the codec object
+ * @verb: verb to allow accessing via regmap
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
+				    unsigned int verb)
+{
+	unsigned int *p = snd_array_new(&codec->vendor_verbs);
+
+	if (!p)
+		return -ENOMEM;
+	*p = verb;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
+
+/*
+ * helper functions
+ */
+
+/* write a pseudo-register value (w/o power sequence) */
+static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
+			 unsigned int val)
+{
+	if (!codec->regmap)
+		return hda_reg_write(codec, reg, val);
+	else
+		return regmap_write(codec->regmap, reg, val);
+}
+
+/**
+ * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @val: value to write
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
+			      unsigned int val)
+{
+	int err;
+
+	err = reg_raw_write(codec, reg, val);
+	if (err == -EAGAIN) {
+		snd_hdac_power_up_pm(codec);
+		err = reg_raw_write(codec, reg, val);
+		snd_hdac_power_down_pm(codec);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
+
+static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
+			unsigned int *val)
+{
+	if (!codec->regmap)
+		return hda_reg_read(codec, reg, val);
+	else
+		return regmap_read(codec->regmap, reg, val);
+}
+
+/**
+ * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @val: pointer to store the read value
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
+			     unsigned int *val)
+{
+	int err;
+
+	err = reg_raw_read(codec, reg, val);
+	if (err == -EAGAIN) {
+		snd_hdac_power_up_pm(codec);
+		err = reg_raw_read(codec, reg, val);
+		snd_hdac_power_down_pm(codec);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw);
+
+/**
+ * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @mask: bit mask to udpate
+ * @val: value to update
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
+			       unsigned int mask, unsigned int val)
+{
+	unsigned int orig;
+	int err;
+
+	val &= mask;
+	err = snd_hdac_regmap_read_raw(codec, reg, &orig);
+	if (err < 0)
+		return err;
+	val |= orig & ~mask;
+	if (val == orig)
+		return 0;
+	err = snd_hdac_regmap_write_raw(codec, reg, val);
+	if (err < 0)
+		return err;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c
new file mode 100644
index 0000000..0a6ce3b
--- /dev/null
+++ b/sound/hda/hdac_sysfs.c
@@ -0,0 +1,406 @@
+/*
+ * sysfs support for HD-audio core device
+ */
+
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include "local.h"
+
+struct hdac_widget_tree {
+	struct kobject *root;
+	struct kobject *afg;
+	struct kobject **nodes;
+};
+
+#define CODEC_ATTR(type)					\
+static ssize_t type##_show(struct device *dev,			\
+			   struct device_attribute *attr,	\
+			   char *buf)				\
+{								\
+	struct hdac_device *codec = dev_to_hdac_dev(dev);	\
+	return sprintf(buf, "0x%x\n", codec->type);		\
+} \
+static DEVICE_ATTR_RO(type)
+
+#define CODEC_ATTR_STR(type)					\
+static ssize_t type##_show(struct device *dev,			\
+			     struct device_attribute *attr,	\
+					char *buf)		\
+{								\
+	struct hdac_device *codec = dev_to_hdac_dev(dev);	\
+	return sprintf(buf, "%s\n",				\
+		       codec->type ? codec->type : "");		\
+} \
+static DEVICE_ATTR_RO(type)
+
+CODEC_ATTR(type);
+CODEC_ATTR(vendor_id);
+CODEC_ATTR(subsystem_id);
+CODEC_ATTR(revision_id);
+CODEC_ATTR(afg);
+CODEC_ATTR(mfg);
+CODEC_ATTR_STR(vendor_name);
+CODEC_ATTR_STR(chip_name);
+
+static struct attribute *hdac_dev_attrs[] = {
+	&dev_attr_type.attr,
+	&dev_attr_vendor_id.attr,
+	&dev_attr_subsystem_id.attr,
+	&dev_attr_revision_id.attr,
+	&dev_attr_afg.attr,
+	&dev_attr_mfg.attr,
+	&dev_attr_vendor_name.attr,
+	&dev_attr_chip_name.attr,
+	NULL
+};
+
+static struct attribute_group hdac_dev_attr_group = {
+	.attrs	= hdac_dev_attrs,
+};
+
+const struct attribute_group *hdac_dev_attr_groups[] = {
+	&hdac_dev_attr_group,
+	NULL
+};
+
+/*
+ * Widget tree sysfs
+ *
+ * This is a tree showing the attributes of each widget.  It appears like
+ * /sys/bus/hdaudioC0D0/widgets/04/caps
+ */
+
+struct widget_attribute;
+
+struct widget_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct hdac_device *codec, hda_nid_t nid,
+			struct widget_attribute *attr, char *buf);
+	ssize_t (*store)(struct hdac_device *codec, hda_nid_t nid,
+			 struct widget_attribute *attr,
+			 const char *buf, size_t count);
+};
+
+static int get_codec_nid(struct kobject *kobj, struct hdac_device **codecp)
+{
+	struct device *dev = kobj_to_dev(kobj->parent->parent);
+	int nid;
+	ssize_t ret;
+
+	ret = kstrtoint(kobj->name, 16, &nid);
+	if (ret < 0)
+		return ret;
+	*codecp = dev_to_hdac_dev(dev);
+	return nid;
+}
+
+static ssize_t widget_attr_show(struct kobject *kobj, struct attribute *attr,
+				char *buf)
+{
+	struct widget_attribute *wid_attr =
+		container_of(attr, struct widget_attribute, attr);
+	struct hdac_device *codec;
+	int nid;
+
+	if (!wid_attr->show)
+		return -EIO;
+	nid = get_codec_nid(kobj, &codec);
+	if (nid < 0)
+		return nid;
+	return wid_attr->show(codec, nid, wid_attr, buf);
+}
+
+static ssize_t widget_attr_store(struct kobject *kobj, struct attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct widget_attribute *wid_attr =
+		container_of(attr, struct widget_attribute, attr);
+	struct hdac_device *codec;
+	int nid;
+
+	if (!wid_attr->store)
+		return -EIO;
+	nid = get_codec_nid(kobj, &codec);
+	if (nid < 0)
+		return nid;
+	return wid_attr->store(codec, nid, wid_attr, buf, count);
+}
+
+static const struct sysfs_ops widget_sysfs_ops = {
+	.show	= widget_attr_show,
+	.store	= widget_attr_store,
+};
+
+static void widget_release(struct kobject *kobj)
+{
+	kfree(kobj);
+}
+
+static struct kobj_type widget_ktype = {
+	.release	= widget_release,
+	.sysfs_ops	= &widget_sysfs_ops,
+};
+
+#define WIDGET_ATTR_RO(_name) \
+	struct widget_attribute wid_attr_##_name = __ATTR_RO(_name)
+#define WIDGET_ATTR_RW(_name) \
+	struct widget_attribute wid_attr_##_name = __ATTR_RW(_name)
+
+static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid,
+			struct widget_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08x\n", get_wcaps(codec, nid));
+}
+
+static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			     struct widget_attribute *attr, char *buf)
+{
+	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
+}
+
+static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
+			    struct widget_attribute *attr, char *buf)
+{
+	unsigned int val;
+
+	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+		return 0;
+	if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
+		return 0;
+	return sprintf(buf, "0x%08x\n", val);
+}
+
+static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid)
+{
+	if (nid == codec->afg || nid == codec->mfg)
+		return true;
+	switch (get_wcaps_type(get_wcaps(codec, nid))) {
+	case AC_WID_AUD_OUT:
+	case AC_WID_AUD_IN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static ssize_t pcm_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			     struct widget_attribute *attr, char *buf)
+{
+	if (!has_pcm_cap(codec, nid))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_PCM));
+}
+
+static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
+				struct widget_attribute *attr, char *buf)
+{
+	if (!has_pcm_cap(codec, nid))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_STREAM));
+}
+
+static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
+				struct widget_attribute *attr, char *buf)
+{
+	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
+}
+
+static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
+				 struct widget_attribute *attr, char *buf)
+{
+	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
+}
+
+static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			       struct widget_attribute *attr, char *buf)
+{
+	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
+}
+
+static ssize_t gpio_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			      struct widget_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP));
+}
+
+static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid,
+				struct widget_attribute *attr, char *buf)
+{
+	hda_nid_t list[32];
+	int i, nconns;
+	ssize_t ret = 0;
+
+	nconns = snd_hdac_get_connections(codec, nid, list, ARRAY_SIZE(list));
+	if (nconns <= 0)
+		return nconns;
+	for (i = 0; i < nconns; i++)
+		ret += sprintf(buf + ret, "%s0x%02x", i ? " " : "", list[i]);
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static WIDGET_ATTR_RO(caps);
+static WIDGET_ATTR_RO(pin_caps);
+static WIDGET_ATTR_RO(pin_cfg);
+static WIDGET_ATTR_RO(pcm_caps);
+static WIDGET_ATTR_RO(pcm_formats);
+static WIDGET_ATTR_RO(amp_in_caps);
+static WIDGET_ATTR_RO(amp_out_caps);
+static WIDGET_ATTR_RO(power_caps);
+static WIDGET_ATTR_RO(gpio_caps);
+static WIDGET_ATTR_RO(connections);
+
+static struct attribute *widget_node_attrs[] = {
+	&wid_attr_caps.attr,
+	&wid_attr_pin_caps.attr,
+	&wid_attr_pin_cfg.attr,
+	&wid_attr_pcm_caps.attr,
+	&wid_attr_pcm_formats.attr,
+	&wid_attr_amp_in_caps.attr,
+	&wid_attr_amp_out_caps.attr,
+	&wid_attr_power_caps.attr,
+	&wid_attr_connections.attr,
+	NULL,
+};
+
+static struct attribute *widget_afg_attrs[] = {
+	&wid_attr_pcm_caps.attr,
+	&wid_attr_pcm_formats.attr,
+	&wid_attr_amp_in_caps.attr,
+	&wid_attr_amp_out_caps.attr,
+	&wid_attr_power_caps.attr,
+	&wid_attr_gpio_caps.attr,
+	NULL,
+};
+
+static const struct attribute_group widget_node_group = {
+	.attrs = widget_node_attrs,
+};
+
+static const struct attribute_group widget_afg_group = {
+	.attrs = widget_afg_attrs,
+};
+
+static void free_widget_node(struct kobject *kobj,
+			     const struct attribute_group *group)
+{
+	if (kobj) {
+		sysfs_remove_group(kobj, group);
+		kobject_put(kobj);
+	}
+}
+
+static void widget_tree_free(struct hdac_device *codec)
+{
+	struct hdac_widget_tree *tree = codec->widgets;
+	struct kobject **p;
+
+	if (!tree)
+		return;
+	free_widget_node(tree->afg, &widget_afg_group);
+	if (tree->nodes) {
+		for (p = tree->nodes; *p; p++)
+			free_widget_node(*p, &widget_node_group);
+		kfree(tree->nodes);
+	}
+	if (tree->root)
+		kobject_put(tree->root);
+	kfree(tree);
+	codec->widgets = NULL;
+}
+
+static int add_widget_node(struct kobject *parent, hda_nid_t nid,
+			   const struct attribute_group *group,
+			   struct kobject **res)
+{
+	struct kobject *kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+	int err;
+
+	if (!kobj)
+		return -ENOMEM;
+	kobject_init(kobj, &widget_ktype);
+	err = kobject_add(kobj, parent, "%02x", nid);
+	if (err < 0)
+		return err;
+	err = sysfs_create_group(kobj, group);
+	if (err < 0) {
+		kobject_put(kobj);
+		return err;
+	}
+
+	*res = kobj;
+	return 0;
+}
+
+static int widget_tree_create(struct hdac_device *codec)
+{
+	struct hdac_widget_tree *tree;
+	int i, err;
+	hda_nid_t nid;
+
+	tree = codec->widgets = kzalloc(sizeof(*tree), GFP_KERNEL);
+	if (!tree)
+		return -ENOMEM;
+
+	tree->root = kobject_create_and_add("widgets", &codec->dev.kobj);
+	if (!tree->root)
+		return -ENOMEM;
+
+	tree->nodes = kcalloc(codec->num_nodes + 1, sizeof(*tree->nodes),
+			      GFP_KERNEL);
+	if (!tree->nodes)
+		return -ENOMEM;
+
+	for (i = 0, nid = codec->start_nid; i < codec->num_nodes; i++, nid++) {
+		err = add_widget_node(tree->root, nid, &widget_node_group,
+				      &tree->nodes[i]);
+		if (err < 0)
+			return err;
+	}
+
+	if (codec->afg) {
+		err = add_widget_node(tree->root, codec->afg,
+				      &widget_afg_group, &tree->afg);
+		if (err < 0)
+			return err;
+	}
+
+	kobject_uevent(tree->root, KOBJ_CHANGE);
+	return 0;
+}
+
+int hda_widget_sysfs_init(struct hdac_device *codec)
+{
+	int err;
+
+	err = widget_tree_create(codec);
+	if (err < 0) {
+		widget_tree_free(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+void hda_widget_sysfs_exit(struct hdac_device *codec)
+{
+	widget_tree_free(codec);
+}
diff --git a/sound/hda/local.h b/sound/hda/local.h
new file mode 100644
index 0000000..d692f41
--- /dev/null
+++ b/sound/hda/local.h
@@ -0,0 +1,23 @@
+/*
+ * Local helper macros and functions for HD-audio core drivers
+ */
+
+#ifndef __HDAC_LOCAL_H
+#define __HDAC_LOCAL_H
+
+#define get_wcaps(codec, nid) \
+	snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
+
+/* get the widget type from widget capability bits */
+static inline int get_wcaps_type(unsigned int wcaps)
+{
+	if (!wcaps)
+		return -1; /* invalid type */
+	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+}
+
+extern const struct attribute_group *hdac_dev_attr_groups[];
+int hda_widget_sysfs_init(struct hdac_device *codec);
+void hda_widget_sysfs_exit(struct hdac_device *codec);
+
+#endif /* __HDAC_LOCAL_H */
diff --git a/sound/hda/trace.c b/sound/hda/trace.c
new file mode 100644
index 0000000..ca2d6bd
--- /dev/null
+++ b/sound/hda/trace.c
@@ -0,0 +1,6 @@
+/*
+ * tracepoint definitions for HD-audio core drivers
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/sound/hda/trace.h b/sound/hda/trace.h
new file mode 100644
index 0000000..33a7eb5
--- /dev/null
+++ b/sound/hda/trace.h
@@ -0,0 +1,62 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hda
+
+#if !defined(__HDAC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HDAC_TRACE_H
+
+#include <linux/tracepoint.h>
+#include <linux/device.h>
+#include <sound/hdaudio.h>
+
+#ifndef HDAC_MSG_MAX
+#define HDAC_MSG_MAX	500
+#endif
+
+struct hdac_bus;
+struct hdac_codec;
+
+TRACE_EVENT(hda_send_cmd,
+	TP_PROTO(struct hdac_bus *bus, unsigned int cmd),
+	TP_ARGS(bus, cmd),
+	TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+	TP_fast_assign(
+		snprintf(__get_str(msg), HDAC_MSG_MAX,
+			 "[%s:%d] val=0x%08x",
+			 dev_name((bus)->dev), (cmd) >> 28, cmd);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(hda_get_response,
+	TP_PROTO(struct hdac_bus *bus, unsigned int addr, unsigned int res),
+	TP_ARGS(bus, addr, res),
+	TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+	TP_fast_assign(
+		snprintf(__get_str(msg), HDAC_MSG_MAX,
+			 "[%s:%d] val=0x%08x",
+			 dev_name((bus)->dev), addr, res);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(hda_unsol_event,
+	TP_PROTO(struct hdac_bus *bus, u32 res, u32 res_ex),
+	TP_ARGS(bus, res, res_ex),
+	TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+	TP_fast_assign(
+		snprintf(__get_str(msg), HDAC_MSG_MAX,
+			 "[%s:%d] res=0x%08x, res_ex=0x%08x",
+			 dev_name((bus)->dev), res_ex & 0x0f, res, res_ex);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+#endif /* __HDAC_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c
index 8884488..2183e9e 100644
--- a/sound/i2c/other/ak4113.c
+++ b/sound/i2c/other/ak4113.c
@@ -73,7 +73,7 @@
 		void *private_data, struct ak4113 **r_ak4113)
 {
 	struct ak4113 *chip;
-	int err = 0;
+	int err;
 	unsigned char reg;
 	static struct snd_device_ops ops = {
 		.dev_free =     snd_ak4113_dev_free,
@@ -109,7 +109,7 @@
 
 __fail:
 	snd_ak4113_free(chip);
-	return err < 0 ? err : -EIO;
+	return err;
 }
 EXPORT_SYMBOL_GPL(snd_ak4113_create);
 
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
index 72332df..4aa719c 100644
--- a/sound/isa/sb/emu8000_synth.c
+++ b/sound/isa/sb/emu8000_synth.c
@@ -34,8 +34,9 @@
 /*
  * create a new hardware dependent device for Emu8000
  */
-static int snd_emu8000_new_device(struct snd_seq_device *dev)
+static int snd_emu8000_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_emu8000 *hw;
 	struct snd_emux *emu;
 
@@ -93,8 +94,9 @@
 /*
  * free all resources
  */
-static int snd_emu8000_delete_device(struct snd_seq_device *dev)
+static int snd_emu8000_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_emu8000 *hw;
 
 	if (dev->driver_data == NULL)
@@ -114,21 +116,14 @@
  *  INIT part
  */
 
-static int __init alsa_emu8000_init(void)
-{
-	
-	static struct snd_seq_dev_ops ops = {
-		snd_emu8000_new_device,
-		snd_emu8000_delete_device,
-	};
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops,
-					      sizeof(struct snd_emu8000*));
-}
+static struct snd_seq_driver emu8000_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_emu8000_probe,
+		.remove = snd_emu8000_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_EMU8000,
+	.argsize = sizeof(struct snd_emu8000 *),
+};
 
-static void __exit alsa_emu8000_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000);
-}
-
-module_init(alsa_emu8000_init)
-module_exit(alsa_emu8000_exit)
+module_snd_seq_driver(emu8000_driver);
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index b5a1970..0608a5a 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -79,13 +79,13 @@
 	if (page < 0 || page > 7) {
 		snd_printk ("FX memset: "
 			"page must be >= 0 and <= 7\n");
-		return -(EINVAL);
+		return -EINVAL;
 	}
 
 	if (addr < 0 || addr > 0x7f) {
 		snd_printk ("FX memset: "
 			"addr must be >= 0 and <= 7f\n");
-		return -(EINVAL);
+		return -EINVAL;
 	}
 
 	if (cnt == 1) {
@@ -118,7 +118,7 @@
 			snd_printk ("FX memset "
 				    "(0x%x, 0x%x, 0x%lx, %d) incomplete\n",
 				    page, addr, (unsigned long) data, cnt);
-			return -(EIO);
+			return -EIO;
 		}
 	}
 
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 33f5ec1..69f76ff 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -793,7 +793,7 @@
     
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) {
 		snd_printk ("download patch failed\n");
-		return -(EIO);
+		return -EIO;
 	}
 
 	return (0);
@@ -831,7 +831,7 @@
     
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
 		snd_printk ("download patch failed\n");	
-		return -(EIO);
+		return -EIO;
 	}
 
 	return (0);
@@ -952,7 +952,7 @@
 	if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
 		snd_printk ("channel selection only "
 			    "possible on 16-bit samples");
-		return -(EINVAL);
+		return -EINVAL;
 	}
 
 	switch (skip) {
@@ -1049,7 +1049,7 @@
 			   NULL, sample_hdr)) {
 		snd_printk ("sample %sdownload refused.\n",
 			    header->size ? "" : "header ");
-		return -(EIO);
+		return -EIO;
 	}
 
 	if (header->size == 0) {
@@ -1075,7 +1075,7 @@
 		if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
 			snd_printk ("download block "
 				    "request refused.\n");
-			return -(EIO);
+			return -EIO;
 		}
 
 		for (i = 0; i < blocksize; i++) {
@@ -1135,12 +1135,12 @@
 			if (dma_ack == -1) {
 				snd_printk ("upload sample "
 					    "DMA ack timeout\n");
-				return -(EIO);
+				return -EIO;
 			} else {
 				snd_printk ("upload sample "
 					    "DMA ack error 0x%x\n",
 					    dma_ack);
-				return -(EIO);
+				return -EIO;
 			}
 		}
 	}
@@ -1181,7 +1181,7 @@
 
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
 		snd_printk ("download alias failed.\n");
-		return -(EIO);
+		return -EIO;
 	}
 
 	dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
@@ -1232,7 +1232,7 @@
 			   msample_hdr)) {
 		snd_printk ("download of multisample failed.\n");
 		kfree(msample_hdr);
-		return -(EIO);
+		return -EIO;
 	}
 
 	dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
@@ -1254,7 +1254,7 @@
     
 	if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
 		snd_printk ("upload multisample failed.\n");
-		return -(EIO);
+		return -EIO;
 	}
     
 	DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
@@ -1273,14 +1273,14 @@
 		if ((val = wavefront_read (dev)) == -1) {
 			snd_printk ("upload multisample failed "
 				    "during sample loop.\n");
-			return -(EIO);
+			return -EIO;
 		}
 		d[0] = val;
 
 		if ((val = wavefront_read (dev)) == -1) {
 			snd_printk ("upload multisample failed "
 				    "during sample loop.\n");
-			return -(EIO);
+			return -EIO;
 		}
 		d[1] = val;
 	
@@ -1315,7 +1315,7 @@
 
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
 		snd_printk ("download drum failed.\n");
-		return -(EIO);
+		return -EIO;
 	}
 
 	return (0);
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index fbcaa54..1e30e84 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -633,19 +633,25 @@
 
 	au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream),
 					   GFP_KERNEL);
-	if (!au1000->stream[PLAYBACK])
+	if (!au1000->stream[PLAYBACK]) {
+		err = -ENOMEM;
 		goto out;
+	}
 	au1000->stream[PLAYBACK]->dma = -1;
 
 	au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream),
 					  GFP_KERNEL);
-	if (!au1000->stream[CAPTURE])
+	if (!au1000->stream[CAPTURE]) {
+		err = -ENOMEM;
 		goto out;
+	}
 	au1000->stream[CAPTURE]->dma = -1;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r)
+	if (!r) {
+		err = -ENODEV;
 		goto out;
+	}
 
 	err = -EBUSY;
 	au1000->ac97_res_port = request_mem_region(r->start, resource_size(r),
diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
index d8cf3e5..6dad515 100644
--- a/sound/oss/dev_table.c
+++ b/sound/oss/dev_table.c
@@ -58,13 +58,13 @@
 
 	if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
 		printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
-		return -(EINVAL);
+		return -EINVAL;
 	}
 	num = sound_alloc_audiodev();
 
 	if (num == -1) {
 		printk(KERN_ERR "sound: Too many audio drivers\n");
-		return -(EBUSY);
+		return -EBUSY;
 	}
 	d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver)));
 	sound_nblocks++;
@@ -79,7 +79,7 @@
 	if (d == NULL || op == NULL) {
 		printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
 		sound_unload_audiodev(num);
-		return -(ENOMEM);
+		return -ENOMEM;
 	}
 	init_waitqueue_head(&op->in_sleeper);
 	init_waitqueue_head(&op->out_sleeper);	
diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c
index 607cee4..b6d19ad 100644
--- a/sound/oss/opl3.c
+++ b/sound/oss/opl3.c
@@ -666,7 +666,7 @@
 	opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data);
 
 	data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
-		 devc->voc[voice].keyon_byte = data;
+	devc->voc[voice].keyon_byte = data;
 	opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data);
 	if (voice_mode == 4)
 		opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
@@ -717,7 +717,7 @@
 
 static void opl3_command    (int io_addr, unsigned int addr, unsigned int val)
 {
-	 int i;
+	int i;
 
 	/*
 	 * The original 2-OP synth requires a quite long delay after writing to a
diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c
index b47a690..57f7d25 100644
--- a/sound/oss/sb_ess.c
+++ b/sound/oss/sb_ess.c
@@ -604,7 +604,7 @@
 	ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
 
 	devc->irq_mode_16 = IMODE_OUTPUT;
-		devc->intr_active_16 = 1;
+	devc->intr_active_16 = 1;
 }
 
 static void ess_audio_output_block
@@ -1183,17 +1183,12 @@
 			chip = "ES1688";
 		}
 
-	    printk ( KERN_INFO "ESS chip %s %s%s\n"
-               , chip
-               , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20
-                 ? "detected"
-                 : "specified"
-                 )
-               , ( devc->sbmo.esstype == ESSTYPE_LIKE20
-                 ? " (kernel 2.0 compatible)"
-                 : ""
-                 )
-               );
+		printk(KERN_INFO "ESS chip %s %s%s\n", chip,
+		       (devc->sbmo.esstype == ESSTYPE_DETECT ||
+			devc->sbmo.esstype == ESSTYPE_LIKE20) ?
+				"detected" : "specified",
+			devc->sbmo.esstype == ESSTYPE_LIKE20 ?
+				" (kernel 2.0 compatible)" : "");
 
 		sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f);
 	} else {
diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c
index f139028..551ee75 100644
--- a/sound/oss/sb_midi.c
+++ b/sound/oss/sb_midi.c
@@ -179,14 +179,14 @@
 	{
 		printk(KERN_WARNING "Sound Blaster:  failed to allocate MIDI memory.\n");
 		sound_unload_mididev(dev);
-		  return;
+		return;
 	}
 	memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations,
 	       sizeof(struct midi_operations));
 
 	if (owner)
-			midi_devs[dev]->owner = owner;
-	
+		midi_devs[dev]->owner = owner;
+
 	midi_devs[dev]->devc = devc;
 
 
diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c
index 9f03983..2226dda 100644
--- a/sound/oss/sys_timer.c
+++ b/sound/oss/sys_timer.c
@@ -50,29 +50,24 @@
 static void
 poll_def_tmr(unsigned long dummy)
 {
+	if (!opened)
+		return;
+	def_tmr.expires = (1) + jiffies;
+	add_timer(&def_tmr);
 
-	if (opened)
-	  {
+	if (!tmr_running)
+		return;
 
-		  {
-			  def_tmr.expires = (1) + jiffies;
-			  add_timer(&def_tmr);
-		  }
+	spin_lock(&lock);
+	tmr_ctr++;
+	curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
 
-		  if (tmr_running)
-		    {
-				spin_lock(&lock);
-			    tmr_ctr++;
-			    curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
+	if (curr_ticks >= next_event_time) {
+		next_event_time = (unsigned long) -1;
+		sequencer_timer(0);
+	}
 
-			    if (curr_ticks >= next_event_time)
-			      {
-				      next_event_time = (unsigned long) -1;
-				      sequencer_timer(0);
-			      }
-				spin_unlock(&lock);
-		    }
-	  }
+	spin_unlock(&lock);
 }
 
 static void
diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c
index f0b4151..fc0ba27 100644
--- a/sound/oss/v_midi.c
+++ b/sound/oss/v_midi.c
@@ -49,13 +49,13 @@
 	unsigned long flags;
 
 	if (devc == NULL)
-		return -(ENXIO);
+		return -ENXIO;
 
 	spin_lock_irqsave(&devc->lock,flags);
 	if (devc->opened)
 	{
 		spin_unlock_irqrestore(&devc->lock,flags);
-		return -(EBUSY);
+		return -EBUSY;
 	}
 	devc->opened = 1;
 	spin_unlock_irqrestore(&devc->lock,flags);
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 5ee2f17..82259ca 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -177,6 +177,7 @@
 { 0x54524123, 0xffffffff, "TR28602",		NULL,		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e03, 0xffffffff, "TLV320AIC27",	NULL,		NULL },
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL,		NULL },
+{ 0x56494120, 0xfffffff0, "VIA1613",		patch_vt1613,	NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",		NULL,		NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",		patch_vt1617a,	NULL }, // modified VT1616 with S/PDIF
 { 0x56494182, 0xffffffff, "VIA1618",		patch_vt1618,   NULL },
@@ -2901,7 +2902,8 @@
  * Return: Zero if successful, or a negative error code on failure.
  */
 
-int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override)
+int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
+			   const struct ac97_quirk *quirk, const char *override)
 {
 	int result;
 
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index ceaac1c..f4234ed 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -3352,6 +3352,33 @@
 }
 
 /*
+ * VIA VT1613 codec
+ */
+static const struct snd_kcontrol_new snd_ac97_controls_vt1613[] = {
+AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),
+};
+
+static int patch_vt1613_specific(struct snd_ac97 *ac97)
+{
+	return patch_build_controls(ac97, &snd_ac97_controls_vt1613[0],
+				    ARRAY_SIZE(snd_ac97_controls_vt1613));
+};
+
+static const struct snd_ac97_build_ops patch_vt1613_ops = {
+	.build_specific	= patch_vt1613_specific
+};
+
+static int patch_vt1613(struct snd_ac97 *ac97)
+{
+	ac97->build_ops = &patch_vt1613_ops;
+
+	ac97->flags |= AC97_HAS_NO_VIDEO;
+	ac97->caps |= AC97_BC_HEADPHONE;
+
+	return 0;
+}
+
+/*
  * VIA VT1616 codec
  */
 static const struct snd_kcontrol_new snd_ac97_controls_vt1616[] = {
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 850a8c9..66ddd98 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -747,7 +747,7 @@
 		snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read);
 }
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
 	{
 		.subvendor = 0x11d4,	/* AD */
 		.subdevice = 0x1889,	/* AD1889 */
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index e5cd7be..1039ecc 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -2376,7 +2376,7 @@
 /*------------------------------------------------------------
    Sampleclock source  controls
  ------------------------------------------------------------*/
-static const char const *sampleclock_sources[] = {
+static const char * const sampleclock_sources[] = {
 	"N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
 	"SMPTE", "Digital1", "Auto", "Network", "Invalid",
 	"Prev Module", "BLU-Link",
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index d5f15c9..42a20c8 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1390,7 +1390,7 @@
  * ac97 mixer section
  */
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
 	{
 		.subvendor = 0x103c,
 		.subdevice = 0x006b,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index a40a2b4..33b2a0a 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1385,8 +1385,8 @@
 					.running)
 			     &&  (!chip->codecs[peer_codecs[codec_type].other2]
 					.running));
-		 }
-		 if (call_function)
+		}
+		if (call_function)
 			snd_azf3328_ctrl_enable_codecs(chip, enable);
 
 		/* ...and adjust clock, too
@@ -2126,7 +2126,8 @@
 static int
 snd_azf3328_pcm(struct snd_azf3328 *chip)
 {
-enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
+	/* pcm devices */
+	enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS };
 
 	struct snd_pcm *pcm;
 	int err;
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 1d0f2ca..6cf464d 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2062,7 +2062,7 @@
 		val = (snd_cmipci_mixer_read(cm, reg.right_reg) >> reg.right_shift) & reg.mask;
 		if (reg.invert)
 			val = reg.mask - val;
-		 ucontrol->value.integer.value[1] = val;
+		ucontrol->value.integer.value[1] = val;
 	}
 	spin_unlock_irq(&cm->reg_lock);
 	return 0;
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 802c33f..963b912 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -43,7 +43,7 @@
 module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds.");
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
 #if 0 /* Not yet confirmed if all 5536 boards are HP only */
 	{
 		.subvendor = PCI_VENDOR_ID_AMD, 
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index a962de0..862db9a 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1283,12 +1283,14 @@
 static int snd_echo_mixer_get(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct echoaudio *chip;
+	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int out = ucontrol->id.index / num_busses_in(chip);
+	unsigned int in = ucontrol->id.index % num_busses_in(chip);
 
-	chip = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.integer.value[0] =
-		chip->monitor_gain[ucontrol->id.index / num_busses_in(chip)]
-			[ucontrol->id.index % num_busses_in(chip)];
+	if (out >= ECHO_MAXAUDIOOUTPUTS || in >= ECHO_MAXAUDIOINPUTS)
+		return -EINVAL;
+
+	ucontrol->value.integer.value[0] = chip->monitor_gain[out][in];
 	return 0;
 }
 
@@ -1297,12 +1299,14 @@
 {
 	struct echoaudio *chip;
 	int changed,  gain;
-	short out, in;
+	unsigned int out, in;
 
 	changed = 0;
 	chip = snd_kcontrol_chip(kcontrol);
 	out = ucontrol->id.index / num_busses_in(chip);
 	in = ucontrol->id.index % num_busses_in(chip);
+	if (out >= ECHO_MAXAUDIOOUTPUTS || in >= ECHO_MAXAUDIOINPUTS)
+		return -EINVAL;
 	gain = ucontrol->value.integer.value[0];
 	if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
 		return -EINVAL;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index b4458a6..54079f5 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -707,6 +707,7 @@
 {
 	struct snd_emu10k1 *emu = data;
 	u32 tmp, tmp2, reg;
+	u32 last_reg = 0;
 	int err;
 
 	for (;;) {
@@ -782,7 +783,15 @@
 			msleep(10);
 			/* Unmute all. Default is muted after a firmware load */
 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
+		} else if (!reg && last_reg) {
+			/* Audio Dock removed */
+			dev_info(emu->card->dev,
+				 "emu1010: Audio Dock detached\n");
+			/* Unmute all */
+			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
 		}
+
+		last_reg = reg;
 	}
 	dev_info(emu->card->dev, "emu1010: firmware thread stopping\n");
 	return 0;
@@ -1325,6 +1334,22 @@
 }
 
 static struct snd_emu_chip_details emu_chip_details[] = {
+	/* Audigy 5/Rx SB1550 */
+	/* Tested by michael@gernoth.net 28 Mar 2015 */
+	/* DSP: CA10300-IAT LF
+	 * DAC: Cirrus Logic CS4382-KQZ
+	 * ADC: Philips 1361T
+	 * AC97: Sigmatel STAC9750
+	 * CA0151: None
+	 */
+	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10241102,
+	 .driver = "Audigy2", .name = "SB Audigy 5/Rx [SB1550]",
+	 .id = "Audigy2",
+	 .emu10k2_chip = 1,
+	 .ca0108_chip = 1,
+	 .spk71 = 1,
+	 .adc_1361t = 1,  /* 24 bit capture instead of 16bit */
+	 .ac97_chip = 1},
 	/* Audigy4 (Not PRO) SB0610 */
 	/* Tested by James@superbug.co.uk 4th April 2006 */
 	/* A_IOCFG bits
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c
index 4c41c90..5457d56 100644
--- a/sound/pci/emu10k1/emu10k1_synth.c
+++ b/sound/pci/emu10k1/emu10k1_synth.c
@@ -29,8 +29,9 @@
 /*
  * create a new hardware dependent device for Emu10k1
  */
-static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
+static int snd_emu10k1_synth_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_emux *emux;
 	struct snd_emu10k1 *hw;
 	struct snd_emu10k1_synth_arg *arg;
@@ -79,8 +80,9 @@
 	return 0;
 }
 
-static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
+static int snd_emu10k1_synth_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_emux *emux;
 	struct snd_emu10k1 *hw;
 	unsigned long flags;
@@ -104,21 +106,14 @@
  *  INIT part
  */
 
-static int __init alsa_emu10k1_synth_init(void)
-{
-	
-	static struct snd_seq_dev_ops ops = {
-		snd_emu10k1_synth_new_device,
-		snd_emu10k1_synth_delete_device,
-	};
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, &ops,
-					      sizeof(struct snd_emu10k1_synth_arg));
-}
+static struct snd_seq_driver emu10k1_synth_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_emu10k1_synth_probe,
+		.remove = snd_emu10k1_synth_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
+	.argsize = sizeof(struct snd_emu10k1_synth_arg),
+};
 
-static void __exit alsa_emu10k1_synth_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH);
-}
-
-module_init(alsa_emu10k1_synth_init)
-module_exit(alsa_emu10k1_synth_exit)
+module_snd_seq_driver(emu10k1_synth_driver);
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 1de3302..55e5716 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -806,6 +806,108 @@
 	.put =          snd_emu1010_internal_clock_put
 };
 
+static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_info *uinfo)
+{
+	static const char * const texts[2] = {
+		"SPDIF", "ADAT"
+	};
+
+	return snd_ctl_enum_info(uinfo, 1, 2, texts);
+}
+
+static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
+	return 0;
+}
+
+static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	u32 tmp;
+	int change = 0;
+
+	val = ucontrol->value.enumerated.item[0];
+	/* Limit: uinfo->value.enumerated.items = 2; */
+	if (val >= 2)
+		return -EINVAL;
+	change = (emu->emu1010.optical_out != val);
+	if (change) {
+		emu->emu1010.optical_out = val;
+		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) |
+			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0);
+		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+	}
+	return change;
+}
+
+static struct snd_kcontrol_new snd_emu1010_optical_out = {
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Optical Output Mode",
+	.count =	1,
+	.info =         snd_emu1010_optical_out_info,
+	.get =          snd_emu1010_optical_out_get,
+	.put =          snd_emu1010_optical_out_put
+};
+
+static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_info *uinfo)
+{
+	static const char * const texts[2] = {
+		"SPDIF", "ADAT"
+	};
+
+	return snd_ctl_enum_info(uinfo, 1, 2, texts);
+}
+
+static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
+	return 0;
+}
+
+static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	u32 tmp;
+	int change = 0;
+
+	val = ucontrol->value.enumerated.item[0];
+	/* Limit: uinfo->value.enumerated.items = 2; */
+	if (val >= 2)
+		return -EINVAL;
+	change = (emu->emu1010.optical_in != val);
+	if (change) {
+		emu->emu1010.optical_in = val;
+		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) |
+			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0);
+		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+	}
+	return change;
+}
+
+static struct snd_kcontrol_new snd_emu1010_optical_in = {
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Optical Input Mode",
+	.count =	1,
+	.info =         snd_emu1010_optical_in_info,
+	.get =          snd_emu1010_optical_in_get,
+	.put =          snd_emu1010_optical_in_put
+};
+
 static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
 					  struct snd_ctl_elem_info *uinfo)
 {
@@ -2051,6 +2153,14 @@
 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
 		if (err < 0)
 			return err;
+		err = snd_ctl_add(card,
+			snd_ctl_new1(&snd_emu1010_optical_out, emu));
+		if (err < 0)
+			return err;
+		err = snd_ctl_add(card,
+			snd_ctl_new1(&snd_emu1010_optical_in, emu));
+		if (err < 0)
+			return err;
 
 	} else if (emu->card_capabilities->emu_model) {
 		/* all other e-mu cards for now */
@@ -2086,6 +2196,14 @@
 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
 		if (err < 0)
 			return err;
+		err = snd_ctl_add(card,
+			snd_ctl_new1(&snd_emu1010_optical_out, emu));
+		if (err < 0)
+			return err;
+		err = snd_ctl_add(card,
+			snd_ctl_new1(&snd_emu1010_optical_in, emu));
+		if (err < 0)
+			return err;
 	}
 
 	if ( emu->card_capabilities->i2c_adc) {
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index 2ca9f2e..53745f4 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -241,31 +241,22 @@
 	struct snd_emu10k1 *emu = entry->private_data;
 	u32 value;
 	u32 value2;
-	unsigned long flags;
 	u32 rate;
 
 	if (emu->card_capabilities->emu_model) {
-		spin_lock_irqsave(&emu->emu_lock, flags);
 		snd_emu1010_fpga_read(emu, 0x38, &value);
-		spin_unlock_irqrestore(&emu->emu_lock, flags);
 		if ((value & 0x1) == 0) {
-			spin_lock_irqsave(&emu->emu_lock, flags);
 			snd_emu1010_fpga_read(emu, 0x2a, &value);
 			snd_emu1010_fpga_read(emu, 0x2b, &value2);
-			spin_unlock_irqrestore(&emu->emu_lock, flags);
 			rate = 0x1770000 / (((value << 5) | value2)+1);	
 			snd_iprintf(buffer, "ADAT Locked : %u\n", rate);
 		} else {
 			snd_iprintf(buffer, "ADAT Unlocked\n");
 		}
-		spin_lock_irqsave(&emu->emu_lock, flags);
 		snd_emu1010_fpga_read(emu, 0x20, &value);
-		spin_unlock_irqrestore(&emu->emu_lock, flags);
 		if ((value & 0x4) == 0) {
-			spin_lock_irqsave(&emu->emu_lock, flags);
 			snd_emu1010_fpga_read(emu, 0x28, &value);
 			snd_emu1010_fpga_read(emu, 0x29, &value2);
-			spin_unlock_irqrestore(&emu->emu_lock, flags);
 			rate = 0x1770000 / (((value << 5) | value2)+1);	
 			snd_iprintf(buffer, "SPDIF Locked : %d\n", rate);
 		} else {
@@ -410,14 +401,11 @@
 {
 	struct snd_emu10k1 *emu = entry->private_data;
 	u32 value;
-	unsigned long flags;
 	int i;
 	snd_iprintf(buffer, "EMU1010 Registers:\n\n");
 
 	for(i = 0; i < 0x40; i+=1) {
-		spin_lock_irqsave(&emu->emu_lock, flags);
 		snd_emu1010_fpga_read(emu, i, &value);
-		spin_unlock_irqrestore(&emu->emu_lock, flags);
 		snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f);
 	}
 }
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 7f0f2c5..a5ed1c1 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -5,6 +5,7 @@
 	select SND_PCM
 	select SND_VMASTER
 	select SND_KCTL_JACK
+	select SND_HDA_CORE
 
 config SND_HDA_INTEL
 	tristate "HD Audio PCI"
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 194f3093..af78fb3 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -4,13 +4,12 @@
 # for haswell power well
 snd-hda-intel-$(CONFIG_SND_HDA_I915) +=	hda_i915.o
 
-snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
+snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 
 # for trace-points
-CFLAGS_hda_codec.o := -I$(src)
 CFLAGS_hda_controller.o := -I$(src)
 
 snd-hda-codec-generic-objs :=	hda_generic.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 3f8706b..03b7399 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -172,7 +172,7 @@
 			     const hda_nid_t *ignore_nids,
 			     unsigned int cond_flags)
 {
-	hda_nid_t nid, end_nid;
+	hda_nid_t nid;
 	short seq, assoc_line_out;
 	struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)];
 	struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)];
@@ -189,8 +189,7 @@
 	memset(hp_out, 0, sizeof(hp_out));
 	assoc_line_out = 0;
 
-	end_nid = codec->start_nid + codec->num_nodes;
-	for (nid = codec->start_nid; nid < end_nid; nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		unsigned int wid_caps = get_wcaps(codec, nid);
 		unsigned int wid_type = get_wcaps_type(wid_caps);
 		unsigned int def_conf;
@@ -410,7 +409,7 @@
 	 * debug prints of the parsed results
 	 */
 	codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
-		   codec->chip_name, cfg->line_outs, cfg->line_out_pins[0],
+		   codec->core.chip_name, cfg->line_outs, cfg->line_out_pins[0],
 		   cfg->line_out_pins[1], cfg->line_out_pins[2],
 		   cfg->line_out_pins[3], cfg->line_out_pins[4],
 		   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
@@ -836,33 +835,33 @@
 			if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
 				break;
 			codec_dbg(codec, "%s: Apply pincfg for %s\n",
-				    codec->chip_name, modelname);
+				    codec->core.chip_name, modelname);
 			snd_hda_apply_pincfgs(codec, fix->v.pins);
 			break;
 		case HDA_FIXUP_VERBS:
 			if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
 				break;
 			codec_dbg(codec, "%s: Apply fix-verbs for %s\n",
-				    codec->chip_name, modelname);
+				    codec->core.chip_name, modelname);
 			snd_hda_add_verbs(codec, fix->v.verbs);
 			break;
 		case HDA_FIXUP_FUNC:
 			if (!fix->v.func)
 				break;
 			codec_dbg(codec, "%s: Apply fix-func for %s\n",
-				    codec->chip_name, modelname);
+				    codec->core.chip_name, modelname);
 			fix->v.func(codec, fix, action);
 			break;
 		case HDA_FIXUP_PINCTLS:
 			if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins)
 				break;
 			codec_dbg(codec, "%s: Apply pinctl for %s\n",
-				    codec->chip_name, modelname);
+				    codec->core.chip_name, modelname);
 			set_pin_targets(codec, fix->v.pins);
 			break;
 		default:
 			codec_err(codec, "%s: Invalid fixup type %d\n",
-				   codec->chip_name, fix->type);
+				   codec->core.chip_name, fix->type);
 			break;
 		}
 		if (!fix->chained || fix->chained_before)
@@ -912,16 +911,16 @@
 		return;
 
 	for (pq = pin_quirk; pq->subvendor; pq++) {
-		if ((codec->subsystem_id & 0xffff0000) != (pq->subvendor << 16))
+		if ((codec->core.subsystem_id & 0xffff0000) != (pq->subvendor << 16))
 			continue;
-		if (codec->vendor_id != pq->codec)
+		if (codec->core.vendor_id != pq->codec)
 			continue;
 		if (pin_config_match(codec, pq->pins)) {
 			codec->fixup_id = pq->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 			codec->fixup_name = pq->name;
 			codec_dbg(codec, "%s: picked fixup %s (pin match)\n",
-				  codec->chip_name, codec->fixup_name);
+				  codec->core.chip_name, codec->fixup_name);
 #endif
 			codec->fixup_list = fixlist;
 			return;
@@ -963,7 +962,7 @@
 		codec->fixup_name = NULL;
 		codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP;
 		codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n",
-			  codec->chip_name);
+			  codec->core.chip_name);
 		return;
 	}
 
@@ -974,7 +973,7 @@
 				codec->fixup_name = models->name;
 				codec->fixup_list = fixlist;
 				codec_dbg(codec, "%s: picked fixup %s (model specified)\n",
-					  codec->chip_name, codec->fixup_name);
+					  codec->core.chip_name, codec->fixup_name);
 				return;
 			}
 			models++;
@@ -987,7 +986,7 @@
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 			name = q->name;
 			codec_dbg(codec, "%s: picked fixup %s (PCI SSID%s)\n",
-				  codec->chip_name, name, q->subdevice_mask ? "" : " - vendor generic");
+				  codec->core.chip_name, name, q->subdevice_mask ? "" : " - vendor generic");
 #endif
 		}
 	}
@@ -996,12 +995,12 @@
 			unsigned int vendorid =
 				q->subdevice | (q->subvendor << 16);
 			unsigned int mask = 0xffff0000 | q->subdevice_mask;
-			if ((codec->subsystem_id & mask) == (vendorid & mask)) {
+			if ((codec->core.subsystem_id & mask) == (vendorid & mask)) {
 				id = q->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 				name = q->name;
 				codec_dbg(codec, "%s: picked fixup %s (codec SSID)\n",
-					  codec->chip_name, name);
+					  codec->core.chip_name, name);
 #endif
 				break;
 			}
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 1e7de08..3364dc0 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -33,30 +33,36 @@
 	DIGBEEP_HZ_MAX = 12000000,	/* 12 KHz */
 };
 
-static void snd_hda_generate_beep(struct work_struct *work)
+/* generate or stop tone */
+static void generate_tone(struct hda_beep *beep, int tone)
 {
-	struct hda_beep *beep =
-		container_of(work, struct hda_beep, beep_work);
 	struct hda_codec *codec = beep->codec;
-	int tone;
 
-	if (!beep->enabled)
-		return;
-
-	tone = beep->tone;
 	if (tone && !beep->playing) {
 		snd_hda_power_up(codec);
+		if (beep->power_hook)
+			beep->power_hook(beep, true);
 		beep->playing = 1;
 	}
-	/* generate tone */
 	snd_hda_codec_write(codec, beep->nid, 0,
 			    AC_VERB_SET_BEEP_CONTROL, tone);
 	if (!tone && beep->playing) {
 		beep->playing = 0;
+		if (beep->power_hook)
+			beep->power_hook(beep, false);
 		snd_hda_power_down(codec);
 	}
 }
 
+static void snd_hda_generate_beep(struct work_struct *work)
+{
+	struct hda_beep *beep =
+		container_of(work, struct hda_beep, beep_work);
+
+	if (beep->enabled)
+		generate_tone(beep, beep->tone);
+}
+
 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
  *
  * The tone frequency of beep generator on IDT/STAC codecs is
@@ -130,10 +136,7 @@
 	cancel_work_sync(&beep->beep_work);
 	if (beep->playing) {
 		/* turn off beep */
-		snd_hda_codec_write(beep->codec, beep->nid, 0,
-				    AC_VERB_SET_BEEP_CONTROL, 0);
-		beep->playing = 0;
-		snd_hda_power_down(beep->codec);
+		generate_tone(beep, 0);
 	}
 }
 
@@ -160,15 +163,15 @@
 	input_dev->name = "HDA Digital PCBeep";
 	input_dev->phys = beep->phys;
 	input_dev->id.bustype = BUS_PCI;
+	input_dev->dev.parent = &codec->card->card_dev;
 
-	input_dev->id.vendor = codec->vendor_id >> 16;
-	input_dev->id.product = codec->vendor_id & 0xffff;
+	input_dev->id.vendor = codec->core.vendor_id >> 16;
+	input_dev->id.product = codec->core.vendor_id & 0xffff;
 	input_dev->id.version = 0x01;
 
 	input_dev->evbit[0] = BIT_MASK(EV_SND);
 	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
 	input_dev->event = snd_hda_beep_event;
-	input_dev->dev.parent = &codec->dev;
 	input_set_drvdata(input_dev, beep);
 
 	beep->dev = input_dev;
@@ -224,7 +227,7 @@
 	if (beep == NULL)
 		return -ENOMEM;
 	snprintf(beep->phys, sizeof(beep->phys),
-		"card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
+		"card%d/codec#%d/beep0", codec->card->number, codec->addr);
 	/* enable linear scale */
 	snd_hda_codec_write_cache(codec, nid, 0,
 		AC_VERB_SET_DIGI_CONVERT_2, 0x01);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index a63b5e0..46524ff 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -40,6 +40,7 @@
 	unsigned int playing:1;
 	struct work_struct beep_work; /* scheduled task for beep event */
 	struct mutex mutex;
+	void (*power_hook)(struct hda_beep *beep, bool on);
 };
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
new file mode 100644
index 0000000..00aa31c
--- /dev/null
+++ b/sound/pci/hda/hda_bind.c
@@ -0,0 +1,273 @@
+/*
+ * HD-audio codec driver binding
+ * Copyright (c) Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ * find a matching codec preset
+ */
+static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
+{
+	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+	struct hda_codec_driver *driver =
+		container_of(drv, struct hda_codec_driver, core);
+	const struct hda_codec_preset *preset;
+	/* check probe_id instead of vendor_id if set */
+	u32 id = codec->probe_id ? codec->probe_id : codec->core.vendor_id;
+
+	for (preset = driver->preset; preset->id; preset++) {
+		u32 mask = preset->mask;
+
+		if (preset->afg && preset->afg != codec->core.afg)
+			continue;
+		if (preset->mfg && preset->mfg != codec->core.mfg)
+			continue;
+		if (!mask)
+			mask = ~0;
+		if (preset->id == (id & mask) &&
+		    (!preset->rev || preset->rev == codec->core.revision_id)) {
+			codec->preset = preset;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* process an unsolicited event */
+static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
+{
+	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+
+	if (codec->patch_ops.unsol_event)
+		codec->patch_ops.unsol_event(codec, ev);
+}
+
+/* reset the codec name from the preset */
+static int codec_refresh_name(struct hda_codec *codec, const char *name)
+{
+	if (name) {
+		kfree(codec->core.chip_name);
+		codec->core.chip_name = kstrdup(name, GFP_KERNEL);
+	}
+	return codec->core.chip_name ? 0 : -ENOMEM;
+}
+
+static int hda_codec_driver_probe(struct device *dev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(dev);
+	struct module *owner = dev->driver->owner;
+	int err;
+
+	if (WARN_ON(!codec->preset))
+		return -EINVAL;
+
+	err = codec_refresh_name(codec, codec->preset->name);
+	if (err < 0)
+		goto error;
+	err = snd_hdac_regmap_init(&codec->core);
+	if (err < 0)
+		goto error;
+
+	if (!try_module_get(owner)) {
+		err = -EINVAL;
+		goto error;
+	}
+
+	err = codec->preset->patch(codec);
+	if (err < 0)
+		goto error_module;
+
+	err = snd_hda_codec_build_pcms(codec);
+	if (err < 0)
+		goto error_module;
+	err = snd_hda_codec_build_controls(codec);
+	if (err < 0)
+		goto error_module;
+	if (codec->card->registered) {
+		err = snd_card_register(codec->card);
+		if (err < 0)
+			goto error_module;
+		snd_hda_codec_register(codec);
+	}
+
+	codec->core.lazy_cache = true;
+	return 0;
+
+ error_module:
+	module_put(owner);
+
+ error:
+	snd_hda_codec_cleanup_for_unbind(codec);
+	return err;
+}
+
+static int hda_codec_driver_remove(struct device *dev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(dev);
+
+	if (codec->patch_ops.free)
+		codec->patch_ops.free(codec);
+	snd_hda_codec_cleanup_for_unbind(codec);
+	module_put(dev->driver->owner);
+	return 0;
+}
+
+static void hda_codec_driver_shutdown(struct device *dev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(dev);
+
+	if (!pm_runtime_suspended(dev) && codec->patch_ops.reboot_notify)
+		codec->patch_ops.reboot_notify(codec);
+}
+
+int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
+			       struct module *owner)
+{
+	drv->core.driver.name = name;
+	drv->core.driver.owner = owner;
+	drv->core.driver.bus = &snd_hda_bus_type;
+	drv->core.driver.probe = hda_codec_driver_probe;
+	drv->core.driver.remove = hda_codec_driver_remove;
+	drv->core.driver.shutdown = hda_codec_driver_shutdown;
+	drv->core.driver.pm = &hda_codec_driver_pm;
+	drv->core.type = HDA_DEV_LEGACY;
+	drv->core.match = hda_codec_match;
+	drv->core.unsol_event = hda_codec_unsol_event;
+	return driver_register(&drv->core.driver);
+}
+EXPORT_SYMBOL_GPL(__hda_codec_driver_register);
+
+void hda_codec_driver_unregister(struct hda_codec_driver *drv)
+{
+	driver_unregister(&drv->core.driver);
+}
+EXPORT_SYMBOL_GPL(hda_codec_driver_unregister);
+
+static inline bool codec_probed(struct hda_codec *codec)
+{
+	return device_attach(hda_codec_dev(codec)) > 0 && codec->preset;
+}
+
+/* try to auto-load and bind the codec module */
+static void codec_bind_module(struct hda_codec *codec)
+{
+#ifdef MODULE
+	request_module("snd-hda-codec-id:%08x", codec->core.vendor_id);
+	if (codec_probed(codec))
+		return;
+	request_module("snd-hda-codec-id:%04x*",
+		       (codec->core.vendor_id >> 16) & 0xffff);
+	if (codec_probed(codec))
+		return;
+#endif
+}
+
+#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
+/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
+static bool is_likely_hdmi_codec(struct hda_codec *codec)
+{
+	hda_nid_t nid;
+
+	for_each_hda_codec_node(nid, codec) {
+		unsigned int wcaps = get_wcaps(codec, nid);
+		switch (get_wcaps_type(wcaps)) {
+		case AC_WID_AUD_IN:
+			return false; /* HDMI parser supports only HDMI out */
+		case AC_WID_AUD_OUT:
+			if (!(wcaps & AC_WCAP_DIGITAL))
+				return false;
+			break;
+		}
+	}
+	return true;
+}
+#else
+/* no HDMI codec parser support */
+#define is_likely_hdmi_codec(codec)	false
+#endif /* CONFIG_SND_HDA_CODEC_HDMI */
+
+static int codec_bind_generic(struct hda_codec *codec)
+{
+	if (codec->probe_id)
+		return -ENODEV;
+
+	if (is_likely_hdmi_codec(codec)) {
+		codec->probe_id = HDA_CODEC_ID_GENERIC_HDMI;
+#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
+		request_module("snd-hda-codec-hdmi");
+#endif
+		if (codec_probed(codec))
+			return 0;
+	}
+
+	codec->probe_id = HDA_CODEC_ID_GENERIC;
+#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
+	request_module("snd-hda-codec-generic");
+#endif
+	if (codec_probed(codec))
+		return 0;
+	return -ENODEV;
+}
+
+#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
+#define is_generic_config(codec) \
+	(codec->modelname && !strcmp(codec->modelname, "generic"))
+#else
+#define is_generic_config(codec)	0
+#endif
+
+/**
+ * snd_hda_codec_configure - (Re-)configure the HD-audio codec
+ * @codec: the HDA codec
+ *
+ * Start parsing of the given codec tree and (re-)initialize the whole
+ * patch instance.
+ *
+ * Returns 0 if successful or a negative error code.
+ */
+int snd_hda_codec_configure(struct hda_codec *codec)
+{
+	int err;
+
+	if (is_generic_config(codec))
+		codec->probe_id = HDA_CODEC_ID_GENERIC;
+	else
+		codec->probe_id = 0;
+
+	err = snd_hdac_device_register(&codec->core);
+	if (err < 0)
+		return err;
+
+	if (!codec->preset)
+		codec_bind_module(codec);
+	if (!codec->preset) {
+		err = codec_bind_generic(codec);
+		if (err < 0) {
+			codec_err(codec, "Unable to bind the codec\n");
+			goto error;
+		}
+	}
+
+	/* audio codec should override the mixer name */
+	if (codec->core.afg || !*codec->card->mixername)
+		snprintf(codec->card->mixername,
+			 sizeof(codec->card->mixername), "%s %s",
+			 codec->core.vendor_name, codec->core.chip_name);
+	return 0;
+
+ error:
+	snd_hdac_device_unregister(&codec->core);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 2fe86d2..e70a7fb 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -26,6 +26,8 @@
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/async.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include <sound/asoundef.h>
@@ -37,97 +39,20 @@
 #include "hda_jack.h"
 #include <sound/hda_hwdep.h>
 
-#define CREATE_TRACE_POINTS
-#include "hda_trace.h"
-
-/*
- * vendor / preset table
- */
-
-struct hda_vendor_id {
-	unsigned int id;
-	const char *name;
-};
-
-/* codec vendor labels */
-static struct hda_vendor_id hda_vendor_ids[] = {
-	{ 0x1002, "ATI" },
-	{ 0x1013, "Cirrus Logic" },
-	{ 0x1057, "Motorola" },
-	{ 0x1095, "Silicon Image" },
-	{ 0x10de, "Nvidia" },
-	{ 0x10ec, "Realtek" },
-	{ 0x1102, "Creative" },
-	{ 0x1106, "VIA" },
-	{ 0x111d, "IDT" },
-	{ 0x11c1, "LSI" },
-	{ 0x11d4, "Analog Devices" },
-	{ 0x13f6, "C-Media" },
-	{ 0x14f1, "Conexant" },
-	{ 0x17e8, "Chrontel" },
-	{ 0x1854, "LG" },
-	{ 0x1aec, "Wolfson Microelectronics" },
-	{ 0x1af4, "QEMU" },
-	{ 0x434d, "C-Media" },
-	{ 0x8086, "Intel" },
-	{ 0x8384, "SigmaTel" },
-	{} /* terminator */
-};
-
-static DEFINE_MUTEX(preset_mutex);
-static LIST_HEAD(hda_preset_tables);
-
-/**
- * snd_hda_add_codec_preset - Add a codec preset to the chain
- * @preset: codec preset table to add
- */
-int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
-{
-	mutex_lock(&preset_mutex);
-	list_add_tail(&preset->list, &hda_preset_tables);
-	mutex_unlock(&preset_mutex);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
-
-/**
- * snd_hda_delete_codec_preset - Delete a codec preset from the chain
- * @preset: codec preset table to delete
- */
-int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
-{
-	mutex_lock(&preset_mutex);
-	list_del(&preset->list);
-	mutex_unlock(&preset_mutex);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset);
-
 #ifdef CONFIG_PM
-#define codec_in_pm(codec)	((codec)->in_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 void hda_call_pm_notify(struct hda_codec *codec, bool power_up)
-{
-	struct hda_bus *bus = codec->bus;
-
-	if ((power_up && codec->pm_up_notified) ||
-	    (!power_up && !codec->pm_up_notified))
-		return;
-	if (bus->ops.pm_notify)
-		bus->ops.pm_notify(bus, power_up);
-	codec->pm_up_notified = power_up;
-}
-
+#define codec_in_pm(codec)	atomic_read(&(codec)->core.in_pm)
+#define hda_codec_is_power_on(codec) \
+	(!pm_runtime_suspended(hda_codec_dev(codec)))
 #else
 #define codec_in_pm(codec)	0
-static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #define hda_codec_is_power_on(codec)	1
-#define hda_call_pm_notify(codec, state) {}
 #endif
 
+#define codec_has_epss(codec) \
+	((codec)->core.power_caps & AC_PWRST_EPSS)
+#define codec_has_clkstop(codec) \
+	((codec)->core.power_caps & AC_PWRST_CLKSTOP)
+
 /**
  * snd_hda_get_jack_location - Give a location string of the jack
  * @cfg: pin default config value
@@ -199,67 +124,32 @@
 EXPORT_SYMBOL_GPL(snd_hda_get_jack_type);
 
 /*
- * Compose a 32bit command word to be sent to the HD-audio controller
+ * Send and receive a verb - passed to exec_verb override for hdac_device
  */
-static inline unsigned int
-make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
-	       unsigned int verb, unsigned int parm)
+static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd,
+			   unsigned int flags, unsigned int *res)
 {
-	u32 val;
-
-	if ((codec->addr & ~0xf) || (nid & ~0x7f) ||
-	    (verb & ~0xfff) || (parm & ~0xffff)) {
-		codec_err(codec, "hda-codec: out of range cmd %x:%x:%x:%x\n",
-		       codec->addr, nid, verb, parm);
-		return ~0;
-	}
-
-	val = (u32)codec->addr << 28;
-	val |= (u32)nid << 20;
-	val |= verb << 8;
-	val |= parm;
-	return val;
-}
-
-/*
- * Send and receive a verb
- */
-static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
-			   int flags, unsigned int *res)
-{
+	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
 	struct hda_bus *bus = codec->bus;
 	int err;
 
 	if (cmd == ~0)
 		return -1;
 
-	if (res)
-		*res = -1;
  again:
-	snd_hda_power_up(codec);
-	mutex_lock(&bus->cmd_mutex);
+	snd_hda_power_up_pm(codec);
+	mutex_lock(&bus->core.cmd_mutex);
 	if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
 		bus->no_response_fallback = 1;
-	for (;;) {
-		trace_hda_send_cmd(codec, cmd);
-		err = bus->ops.command(bus, cmd);
-		if (err != -EAGAIN)
-			break;
-		/* process pending verbs */
-		bus->ops.get_response(bus, codec->addr);
-	}
-	if (!err && res) {
-		*res = bus->ops.get_response(bus, codec->addr);
-		trace_hda_get_response(codec, *res);
-	}
+	err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr,
+					      cmd, res);
 	bus->no_response_fallback = 0;
-	mutex_unlock(&bus->cmd_mutex);
-	snd_hda_power_down(codec);
-	if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
+	mutex_unlock(&bus->core.cmd_mutex);
+	snd_hda_power_down_pm(codec);
+	if (!codec_in_pm(codec) && res && err < 0 && bus->rirb_error) {
 		if (bus->response_reset) {
 			codec_dbg(codec,
 				  "resetting BUS due to fatal communication error\n");
-			trace_hda_bus_reset(bus);
 			bus->ops.bus_reset(bus);
 		}
 		goto again;
@@ -286,9 +176,9 @@
 				int flags,
 				unsigned int verb, unsigned int parm)
 {
-	unsigned cmd = make_codec_cmd(codec, nid, flags, verb, parm);
+	unsigned int cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm);
 	unsigned int res;
-	if (codec_exec_verb(codec, cmd, flags, &res))
+	if (snd_hdac_exec_verb(&codec->core, cmd, flags, &res))
 		return -1;
 	return res;
 }
@@ -309,10 +199,8 @@
 int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
 			unsigned int verb, unsigned int parm)
 {
-	unsigned int cmd = make_codec_cmd(codec, nid, flags, verb, parm);
-	unsigned int res;
-	return codec_exec_verb(codec, cmd, flags,
-			       codec->bus->sync_write ? &res : NULL);
+	unsigned int cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm);
+	return snd_hdac_exec_verb(&codec->core, cmd, flags, NULL);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_write);
 
@@ -331,30 +219,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_sequence_write);
 
-/**
- * snd_hda_get_sub_nodes - get the range of sub nodes
- * @codec: the HDA codec
- * @nid: NID to parse
- * @start_id: the pointer to store the start NID
- *
- * Parse the NID and store the start NID of its sub-nodes.
- * Returns the number of sub-nodes.
- */
-int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
-			  hda_nid_t *start_id)
-{
-	unsigned int parm;
-
-	parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT);
-	if (parm == -1) {
-		*start_id = 0;
-		return 0;
-	}
-	*start_id = (parm >> 16) & 0x7fff;
-	return (int)(parm & 0x7fff);
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes);
-
 /* connection list element */
 struct hda_conn_list {
 	struct list_head list;
@@ -495,128 +359,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_get_connections);
 
-/* return CONNLIST_LEN parameter of the given widget */
-static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
-{
-	unsigned int wcaps = get_wcaps(codec, nid);
-	unsigned int parm;
-
-	if (!(wcaps & AC_WCAP_CONN_LIST) &&
-	    get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
-		return 0;
-
-	parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
-	if (parm == -1)
-		parm = 0;
-	return parm;
-}
-
-int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid)
-{
-	return snd_hda_get_raw_connections(codec, nid, NULL, 0);
-}
-
-/**
- * snd_hda_get_raw_connections - copy connection list without cache
- * @codec: the HDA codec
- * @nid: NID to parse
- * @conn_list: connection list array
- * @max_conns: max. number of connections to store
- *
- * Like snd_hda_get_connections(), copy the connection list but without
- * checking through the connection-list cache.
- * Currently called only from hda_proc.c, so not exported.
- */
-int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
-				hda_nid_t *conn_list, int max_conns)
-{
-	unsigned int parm;
-	int i, conn_len, conns;
-	unsigned int shift, num_elems, mask;
-	hda_nid_t prev_nid;
-	int null_count = 0;
-
-	parm = get_num_conns(codec, nid);
-	if (!parm)
-		return 0;
-
-	if (parm & AC_CLIST_LONG) {
-		/* long form */
-		shift = 16;
-		num_elems = 2;
-	} else {
-		/* short form */
-		shift = 8;
-		num_elems = 4;
-	}
-	conn_len = parm & AC_CLIST_LENGTH;
-	mask = (1 << (shift-1)) - 1;
-
-	if (!conn_len)
-		return 0; /* no connection */
-
-	if (conn_len == 1) {
-		/* single connection */
-		parm = snd_hda_codec_read(codec, nid, 0,
-					  AC_VERB_GET_CONNECT_LIST, 0);
-		if (parm == -1 && codec->bus->rirb_error)
-			return -EIO;
-		if (conn_list)
-			conn_list[0] = parm & mask;
-		return 1;
-	}
-
-	/* multi connection */
-	conns = 0;
-	prev_nid = 0;
-	for (i = 0; i < conn_len; i++) {
-		int range_val;
-		hda_nid_t val, n;
-
-		if (i % num_elems == 0) {
-			parm = snd_hda_codec_read(codec, nid, 0,
-						  AC_VERB_GET_CONNECT_LIST, i);
-			if (parm == -1 && codec->bus->rirb_error)
-				return -EIO;
-		}
-		range_val = !!(parm & (1 << (shift-1))); /* ranges */
-		val = parm & mask;
-		if (val == 0 && null_count++) {  /* no second chance */
-			codec_dbg(codec,
-				  "invalid CONNECT_LIST verb %x[%i]:%x\n",
-				    nid, i, parm);
-			return 0;
-		}
-		parm >>= shift;
-		if (range_val) {
-			/* ranges between the previous and this one */
-			if (!prev_nid || prev_nid >= val) {
-				codec_warn(codec,
-					   "invalid dep_range_val %x:%x\n",
-					   prev_nid, val);
-				continue;
-			}
-			for (n = prev_nid + 1; n <= val; n++) {
-				if (conn_list) {
-					if (conns >= max_conns)
-						return -ENOSPC;
-					conn_list[conns] = n;
-				}
-				conns++;
-			}
-		} else {
-			if (conn_list) {
-				if (conns >= max_conns)
-					return -ENOSPC;
-				conn_list[conns] = val;
-			}
-			conns++;
-		}
-		prev_nid = val;
-	}
-	return conns;
-}
-
 /**
  * snd_hda_override_conn_list - add/modify the connection-list to cache
  * @codec: the HDA codec
@@ -741,90 +483,6 @@
 	return devices;
 }
 
-/**
- * snd_hda_queue_unsol_event - add an unsolicited event to queue
- * @bus: the BUS
- * @res: unsolicited event (lower 32bit of RIRB entry)
- * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
- *
- * Adds the given event to the queue.  The events are processed in
- * the workqueue asynchronously.  Call this function in the interrupt
- * hanlder when RIRB receives an unsolicited event.
- *
- * Returns 0 if successful, or a negative error code.
- */
-int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
-{
-	struct hda_bus_unsolicited *unsol;
-	unsigned int wp;
-
-	if (!bus || !bus->workq)
-		return 0;
-
-	trace_hda_unsol_event(bus, res, res_ex);
-	unsol = bus->unsol;
-	if (!unsol)
-		return 0;
-
-	wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE;
-	unsol->wp = wp;
-
-	wp <<= 1;
-	unsol->queue[wp] = res;
-	unsol->queue[wp + 1] = res_ex;
-
-	queue_work(bus->workq, &unsol->work);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event);
-
-/*
- * process queued unsolicited events
- */
-static void process_unsol_events(struct work_struct *work)
-{
-	struct hda_bus_unsolicited *unsol =
-		container_of(work, struct hda_bus_unsolicited, work);
-	struct hda_bus *bus = unsol->bus;
-	struct hda_codec *codec;
-	unsigned int rp, caddr, res;
-
-	while (unsol->rp != unsol->wp) {
-		rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE;
-		unsol->rp = rp;
-		rp <<= 1;
-		res = unsol->queue[rp];
-		caddr = unsol->queue[rp + 1];
-		if (!(caddr & (1 << 4))) /* no unsolicited event? */
-			continue;
-		codec = bus->caddr_tbl[caddr & 0x0f];
-		if (codec && codec->patch_ops.unsol_event)
-			codec->patch_ops.unsol_event(codec, res);
-	}
-}
-
-/*
- * initialize unsolicited queue
- */
-static int init_unsol_queue(struct hda_bus *bus)
-{
-	struct hda_bus_unsolicited *unsol;
-
-	if (bus->unsol) /* already initialized */
-		return 0;
-
-	unsol = kzalloc(sizeof(*unsol), GFP_KERNEL);
-	if (!unsol) {
-		dev_err(bus->card->dev, "can't allocate unsolicited queue\n");
-		return -ENOMEM;
-	}
-	INIT_WORK(&unsol->work, process_unsol_events);
-	unsol->bus = bus;
-	bus->unsol = unsol;
-	return 0;
-}
-
 /*
  * destructor
  */
@@ -832,16 +490,9 @@
 {
 	if (!bus)
 		return;
-
-	WARN_ON(!list_empty(&bus->codec_list));
-	if (bus->workq)
-		flush_workqueue(bus->workq);
-	kfree(bus->unsol);
 	if (bus->ops.private_free)
 		bus->ops.private_free(bus);
-	if (bus->workq)
-		destroy_workqueue(bus->workq);
-
+	snd_hdac_bus_exit(&bus->core);
 	kfree(bus);
 }
 
@@ -858,17 +509,35 @@
 	return 0;
 }
 
+/* hdac_bus_ops translations */
+static int _hda_bus_command(struct hdac_bus *_bus, unsigned int cmd)
+{
+	struct hda_bus *bus = container_of(_bus, struct hda_bus, core);
+	return bus->ops.command(bus, cmd);
+}
+
+static int _hda_bus_get_response(struct hdac_bus *_bus, unsigned int addr,
+				 unsigned int *res)
+{
+	struct hda_bus *bus = container_of(_bus, struct hda_bus, core);
+	*res = bus->ops.get_response(bus, addr);
+	return bus->rirb_error ? -EIO : 0;
+}
+
+static const struct hdac_bus_ops bus_ops = {
+	.command = _hda_bus_command,
+	.get_response = _hda_bus_get_response,
+};
+
 /**
  * snd_hda_bus_new - create a HDA bus
  * @card: the card entry
- * @temp: the template for hda_bus information
  * @busp: the pointer to store the created bus instance
  *
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hda_bus_new(struct snd_card *card,
-			      const struct hda_bus_template *temp,
-			      struct hda_bus **busp)
+		    struct hda_bus **busp)
 {
 	struct hda_bus *bus;
 	int err;
@@ -877,40 +546,21 @@
 		.dev_free = snd_hda_bus_dev_free,
 	};
 
-	if (snd_BUG_ON(!temp))
-		return -EINVAL;
-	if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response))
-		return -EINVAL;
-
 	if (busp)
 		*busp = NULL;
 
 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-	if (bus == NULL) {
-		dev_err(card->dev, "can't allocate struct hda_bus\n");
+	if (!bus)
 		return -ENOMEM;
+
+	err = snd_hdac_bus_init(&bus->core, card->dev, &bus_ops);
+	if (err < 0) {
+		kfree(bus);
+		return err;
 	}
 
 	bus->card = card;
-	bus->private_data = temp->private_data;
-	bus->pci = temp->pci;
-	bus->modelname = temp->modelname;
-	bus->power_save = temp->power_save;
-	bus->ops = temp->ops;
-
-	mutex_init(&bus->cmd_mutex);
 	mutex_init(&bus->prepare_mutex);
-	INIT_LIST_HEAD(&bus->codec_list);
-
-	snprintf(bus->workq_name, sizeof(bus->workq_name),
-		 "hd-audio%d", card->number);
-	bus->workq = create_singlethread_workqueue(bus->workq_name);
-	if (!bus->workq) {
-		dev_err(card->dev, "cannot create workqueue %s\n",
-			   bus->workq_name);
-		kfree(bus);
-		return -ENOMEM;
-	}
 
 	err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
 	if (err < 0) {
@@ -923,140 +573,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_bus_new);
 
-#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
-#define is_generic_config(codec) \
-	(codec->modelname && !strcmp(codec->modelname, "generic"))
-#else
-#define is_generic_config(codec)	0
-#endif
-
-#ifdef MODULE
-#define HDA_MODREQ_MAX_COUNT	2	/* two request_modules()'s */
-#else
-#define HDA_MODREQ_MAX_COUNT	0	/* all presets are statically linked */
-#endif
-
-/*
- * find a matching codec preset
- */
-static const struct hda_codec_preset *
-find_codec_preset(struct hda_codec *codec)
-{
-	struct hda_codec_preset_list *tbl;
-	const struct hda_codec_preset *preset;
-	unsigned int mod_requested = 0;
-
- again:
-	mutex_lock(&preset_mutex);
-	list_for_each_entry(tbl, &hda_preset_tables, list) {
-		if (!try_module_get(tbl->owner)) {
-			codec_err(codec, "cannot module_get\n");
-			continue;
-		}
-		for (preset = tbl->preset; preset->id; preset++) {
-			u32 mask = preset->mask;
-			if (preset->afg && preset->afg != codec->afg)
-				continue;
-			if (preset->mfg && preset->mfg != codec->mfg)
-				continue;
-			if (!mask)
-				mask = ~0;
-			if (preset->id == (codec->vendor_id & mask) &&
-			    (!preset->rev ||
-			     preset->rev == codec->revision_id)) {
-				mutex_unlock(&preset_mutex);
-				codec->owner = tbl->owner;
-				return preset;
-			}
-		}
-		module_put(tbl->owner);
-	}
-	mutex_unlock(&preset_mutex);
-
-	if (mod_requested < HDA_MODREQ_MAX_COUNT) {
-		if (!mod_requested)
-			request_module("snd-hda-codec-id:%08x",
-				       codec->vendor_id);
-		else
-			request_module("snd-hda-codec-id:%04x*",
-				       (codec->vendor_id >> 16) & 0xffff);
-		mod_requested++;
-		goto again;
-	}
-	return NULL;
-}
-
-/*
- * get_codec_name - store the codec name
- */
-static int get_codec_name(struct hda_codec *codec)
-{
-	const struct hda_vendor_id *c;
-	const char *vendor = NULL;
-	u16 vendor_id = codec->vendor_id >> 16;
-	char tmp[16];
-
-	if (codec->vendor_name)
-		goto get_chip_name;
-
-	for (c = hda_vendor_ids; c->id; c++) {
-		if (c->id == vendor_id) {
-			vendor = c->name;
-			break;
-		}
-	}
-	if (!vendor) {
-		sprintf(tmp, "Generic %04x", vendor_id);
-		vendor = tmp;
-	}
-	codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
-	if (!codec->vendor_name)
-		return -ENOMEM;
-
- get_chip_name:
-	if (codec->chip_name)
-		return 0;
-
-	if (codec->preset && codec->preset->name)
-		codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
-	else {
-		sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
-		codec->chip_name = kstrdup(tmp, GFP_KERNEL);
-	}
-	if (!codec->chip_name)
-		return -ENOMEM;
-	return 0;
-}
-
-/*
- * look for an AFG and MFG nodes
- */
-static void setup_fg_nodes(struct hda_codec *codec)
-{
-	int i, total_nodes, function_id;
-	hda_nid_t nid;
-
-	total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
-	for (i = 0; i < total_nodes; i++, nid++) {
-		function_id = snd_hda_param_read(codec, nid,
-						AC_PAR_FUNCTION_TYPE);
-		switch (function_id & 0xff) {
-		case AC_GRP_AUDIO_FUNCTION:
-			codec->afg = nid;
-			codec->afg_function_id = function_id & 0xff;
-			codec->afg_unsol = (function_id >> 8) & 1;
-			break;
-		case AC_GRP_MODEM_FUNCTION:
-			codec->mfg = nid;
-			codec->mfg_function_id = function_id & 0xff;
-			codec->mfg_unsol = (function_id >> 8) & 1;
-			break;
-		default:
-			break;
-		}
-	}
-}
-
 /*
  * read widget caps for each widget and store in cache
  */
@@ -1065,25 +581,22 @@
 	int i;
 	hda_nid_t nid;
 
-	codec->num_nodes = snd_hda_get_sub_nodes(codec, fg_node,
-						 &codec->start_nid);
-	codec->wcaps = kmalloc(codec->num_nodes * 4, GFP_KERNEL);
+	codec->wcaps = kmalloc(codec->core.num_nodes * 4, GFP_KERNEL);
 	if (!codec->wcaps)
 		return -ENOMEM;
-	nid = codec->start_nid;
-	for (i = 0; i < codec->num_nodes; i++, nid++)
-		codec->wcaps[i] = snd_hda_param_read(codec, nid,
-						     AC_PAR_AUDIO_WIDGET_CAP);
+	nid = codec->core.start_nid;
+	for (i = 0; i < codec->core.num_nodes; i++, nid++)
+		codec->wcaps[i] = snd_hdac_read_parm_uncached(&codec->core,
+					nid, AC_PAR_AUDIO_WIDGET_CAP);
 	return 0;
 }
 
 /* read all pin default configurations and save codec->init_pins */
 static int read_pin_defaults(struct hda_codec *codec)
 {
-	int i;
-	hda_nid_t nid = codec->start_nid;
+	hda_nid_t nid;
 
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		struct hda_pincfg *pin;
 		unsigned int wcaps = get_wcaps(codec, nid);
 		unsigned int wid_type = get_wcaps_type(wcaps);
@@ -1290,14 +803,10 @@
 	if (!codec->jackpoll_interval)
 		return;
 
-	queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
-			   codec->jackpoll_interval);
+	schedule_delayed_work(&codec->jackpoll_work,
+			      codec->jackpoll_interval);
 }
 
-static void init_hda_cache(struct hda_cache_rec *cache,
-			   unsigned int record_size);
-static void free_hda_cache(struct hda_cache_rec *cache);
-
 /* release all pincfg lists */
 static void free_init_pincfgs(struct hda_codec *codec)
 {
@@ -1339,70 +848,117 @@
 }
 
 /*
- * Dynamic symbol binding for the codec parsers
+ * PCM device
  */
-
-#define load_parser(codec, sym) \
-	((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym))
-
-static void unload_parser(struct hda_codec *codec)
+static void release_pcm(struct kref *kref)
 {
-	if (codec->parser)
-		symbol_put_addr(codec->parser);
-	codec->parser = NULL;
+	struct hda_pcm *pcm = container_of(kref, struct hda_pcm, kref);
+
+	if (pcm->pcm)
+		snd_device_free(pcm->codec->card, pcm->pcm);
+	clear_bit(pcm->device, pcm->codec->bus->pcm_dev_bits);
+	kfree(pcm->name);
+	kfree(pcm);
 }
 
+void snd_hda_codec_pcm_put(struct hda_pcm *pcm)
+{
+	kref_put(&pcm->kref, release_pcm);
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_put);
+
+struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
+				      const char *fmt, ...)
+{
+	struct hda_pcm *pcm;
+	va_list args;
+
+	va_start(args, fmt);
+	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+	if (!pcm)
+		return NULL;
+
+	pcm->codec = codec;
+	kref_init(&pcm->kref);
+	pcm->name = kvasprintf(GFP_KERNEL, fmt, args);
+	if (!pcm->name) {
+		kfree(pcm);
+		return NULL;
+	}
+
+	list_add_tail(&pcm->list, &codec->pcm_list_head);
+	return pcm;
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new);
+
 /*
  * codec destructor
  */
-static void snd_hda_codec_free(struct hda_codec *codec)
+static void codec_release_pcms(struct hda_codec *codec)
 {
-	if (!codec)
-		return;
-	cancel_delayed_work_sync(&codec->jackpoll_work);
-	snd_hda_jack_tbl_clear(codec);
-	free_init_pincfgs(codec);
-#ifdef CONFIG_PM
-	cancel_delayed_work(&codec->power_work);
-	flush_workqueue(codec->bus->workq);
-#endif
-	list_del(&codec->list);
-	snd_array_free(&codec->mixers);
-	snd_array_free(&codec->nids);
-	snd_array_free(&codec->cvt_setups);
-	snd_array_free(&codec->spdif_out);
-	remove_conn_list(codec);
-	codec->bus->caddr_tbl[codec->addr] = NULL;
-	if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
-	hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
-	snd_hda_sysfs_clear(codec);
-	unload_parser(codec);
-	module_put(codec->owner);
-	free_hda_cache(&codec->amp_cache);
-	free_hda_cache(&codec->cmd_cache);
-	kfree(codec->vendor_name);
-	kfree(codec->chip_name);
-	kfree(codec->modelname);
-	kfree(codec->wcaps);
-	codec->bus->num_codecs--;
-	put_device(&codec->dev);
+	struct hda_pcm *pcm, *n;
+
+	list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) {
+		list_del_init(&pcm->list);
+		if (pcm->pcm)
+			snd_device_disconnect(codec->card, pcm->pcm);
+		snd_hda_codec_pcm_put(pcm);
+	}
 }
 
-static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
-				hda_nid_t fg, unsigned int power_state);
+void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
+{
+	if (codec->registered) {
+		/* pm_runtime_put() is called in snd_hdac_device_exit() */
+		pm_runtime_get_noresume(hda_codec_dev(codec));
+		pm_runtime_disable(hda_codec_dev(codec));
+		codec->registered = 0;
+	}
+
+	cancel_delayed_work_sync(&codec->jackpoll_work);
+	if (!codec->in_freeing)
+		snd_hda_ctls_clear(codec);
+	codec_release_pcms(codec);
+	snd_hda_detach_beep_device(codec);
+	memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
+	snd_hda_jack_tbl_clear(codec);
+	codec->proc_widget_hook = NULL;
+	codec->spec = NULL;
+
+	/* free only driver_pins so that init_pins + user_pins are restored */
+	snd_array_free(&codec->driver_pins);
+	snd_array_free(&codec->cvt_setups);
+	snd_array_free(&codec->spdif_out);
+	snd_array_free(&codec->verbs);
+	codec->preset = NULL;
+	codec->slave_dig_outs = NULL;
+	codec->spdif_status_reset = 0;
+	snd_array_free(&codec->mixers);
+	snd_array_free(&codec->nids);
+	remove_conn_list(codec);
+	snd_hdac_regmap_exit(&codec->core);
+}
 
 static unsigned int hda_set_power_state(struct hda_codec *codec,
 				unsigned int power_state);
 
+/* also called from hda_bind.c */
+void snd_hda_codec_register(struct hda_codec *codec)
+{
+	if (codec->registered)
+		return;
+	if (device_is_registered(hda_codec_dev(codec))) {
+		snd_hda_register_beep_device(codec);
+		pm_runtime_enable(hda_codec_dev(codec));
+		/* it was powered up in snd_hda_codec_new(), now all done */
+		snd_hda_power_down(codec);
+		codec->registered = 1;
+	}
+}
+
 static int snd_hda_codec_dev_register(struct snd_device *device)
 {
-	struct hda_codec *codec = device->device_data;
-	int err = device_add(&codec->dev);
-
-	if (err < 0)
-		return err;
-	snd_hda_register_beep_device(codec);
+	snd_hda_codec_register(device->device_data);
 	return 0;
 }
 
@@ -1411,20 +967,29 @@
 	struct hda_codec *codec = device->device_data;
 
 	snd_hda_detach_beep_device(codec);
-	device_del(&codec->dev);
 	return 0;
 }
 
 static int snd_hda_codec_dev_free(struct snd_device *device)
 {
-	snd_hda_codec_free(device->device_data);
+	struct hda_codec *codec = device->device_data;
+
+	codec->in_freeing = 1;
+	snd_hdac_device_unregister(&codec->core);
+	put_device(hda_codec_dev(codec));
 	return 0;
 }
 
-/* just free the container */
 static void snd_hda_codec_dev_release(struct device *dev)
 {
-	kfree(container_of(dev, struct hda_codec, dev));
+	struct hda_codec *codec = dev_to_hda_codec(dev);
+
+	free_init_pincfgs(codec);
+	snd_hdac_device_exit(&codec->core);
+	snd_hda_sysfs_clear(codec);
+	kfree(codec->modelname);
+	kfree(codec->wcaps);
+	kfree(codec);
 }
 
 /**
@@ -1435,9 +1000,8 @@
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_codec_new(struct hda_bus *bus,
-				unsigned int codec_addr,
-				struct hda_codec **codecp)
+int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
+		      unsigned int codec_addr, struct hda_codec **codecp)
 {
 	struct hda_codec *codec;
 	char component[31];
@@ -1454,35 +1018,27 @@
 	if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
 		return -EINVAL;
 
-	if (bus->caddr_tbl[codec_addr]) {
-		dev_err(bus->card->dev,
-			"address 0x%x is already occupied\n",
-			codec_addr);
-		return -EBUSY;
-	}
-
 	codec = kzalloc(sizeof(*codec), GFP_KERNEL);
-	if (codec == NULL) {
-		dev_err(bus->card->dev, "can't allocate struct hda_codec\n");
+	if (!codec)
 		return -ENOMEM;
+
+	sprintf(component, "hdaudioC%dD%d", card->number, codec_addr);
+	err = snd_hdac_device_init(&codec->core, &bus->core, component,
+				   codec_addr);
+	if (err < 0) {
+		kfree(codec);
+		return err;
 	}
 
-	device_initialize(&codec->dev);
-	codec->dev.parent = &bus->card->card_dev;
-	codec->dev.class = sound_class;
-	codec->dev.release = snd_hda_codec_dev_release;
-	codec->dev.groups = snd_hda_dev_attr_groups;
-	dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number,
-		     codec_addr);
-	dev_set_drvdata(&codec->dev, codec); /* for sysfs */
+	codec->core.dev.release = snd_hda_codec_dev_release;
+	codec->core.type = HDA_DEV_LEGACY;
+	codec->core.exec_verb = codec_exec_verb;
 
 	codec->bus = bus;
+	codec->card = card;
 	codec->addr = codec_addr;
 	mutex_init(&codec->spdif_mutex);
 	mutex_init(&codec->control_mutex);
-	mutex_init(&codec->hash_mutex);
-	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
-	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
 	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
 	snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
 	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
@@ -1492,19 +1048,14 @@
 	snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
 	snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
 	INIT_LIST_HEAD(&codec->conn_list);
+	INIT_LIST_HEAD(&codec->pcm_list_head);
 
 	INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
 	codec->depop_delay = -1;
 	codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
 
 #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.
-	 * the caller has to power down appropriatley after initialization
-	 * phase.
-	 */
-	hda_keep_power_on(codec);
+	codec->power_jiffies = jiffies;
 #endif
 
 	snd_hda_sysfs_init(codec);
@@ -1517,59 +1068,14 @@
 		}
 	}
 
-	list_add_tail(&codec->list, &bus->codec_list);
-	bus->num_codecs++;
-
-	bus->caddr_tbl[codec_addr] = codec;
-
-	codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT,
-					      AC_PAR_VENDOR_ID);
-	if (codec->vendor_id == -1)
-		/* read again, hopefully the access method was corrected
-		 * in the last read...
-		 */
-		codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT,
-						      AC_PAR_VENDOR_ID);
-	codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT,
-						 AC_PAR_SUBSYSTEM_ID);
-	codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT,
-						AC_PAR_REV_ID);
-
-	setup_fg_nodes(codec);
-	if (!codec->afg && !codec->mfg) {
-		dev_err(bus->card->dev, "no AFG or MFG node found\n");
-		err = -ENODEV;
-		goto error;
-	}
-
-	fg = codec->afg ? codec->afg : codec->mfg;
+	fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
 	err = read_widget_caps(codec, fg);
-	if (err < 0) {
-		dev_err(bus->card->dev, "cannot malloc\n");
+	if (err < 0)
 		goto error;
-	}
 	err = read_pin_defaults(codec);
 	if (err < 0)
 		goto error;
 
-	if (!codec->subsystem_id) {
-		codec->subsystem_id =
-			snd_hda_codec_read(codec, fg, 0,
-					   AC_VERB_GET_SUBSYSTEM_ID, 0);
-	}
-
-#ifdef CONFIG_PM
-	codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg,
-					AC_PWRST_CLKSTOP);
-#endif
-	codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
-					AC_PWRST_EPSS);
-#ifdef CONFIG_PM
-	if (!codec->d3_stop_clk || !codec->epss)
-		bus->power_keep_link_on = 1;
-#endif
-
-
 	/* power-up all before initialization */
 	hda_set_power_state(codec, AC_PWRST_D0);
 
@@ -1577,11 +1083,11 @@
 
 	snd_hda_create_hwdep(codec);
 
-	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
-		codec->subsystem_id, codec->revision_id);
-	snd_component_add(codec->bus->card, component);
+	sprintf(component, "HDA:%08x,%08x,%08x", codec->core.vendor_id,
+		codec->core.subsystem_id, codec->core.revision_id);
+	snd_component_add(card, component);
 
-	err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops);
+	err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops);
 	if (err < 0)
 		goto error;
 
@@ -1590,7 +1096,7 @@
 	return 0;
 
  error:
-	snd_hda_codec_free(codec);
+	put_device(hda_codec_dev(codec));
 	return err;
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_new);
@@ -1607,16 +1113,18 @@
 	hda_nid_t fg;
 	int err;
 
+	err = snd_hdac_refresh_widgets(&codec->core);
+	if (err < 0)
+		return err;
+
 	/* Assume the function group node does not change,
 	 * only the widget nodes may change.
 	 */
 	kfree(codec->wcaps);
-	fg = codec->afg ? codec->afg : codec->mfg;
+	fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
 	err = read_widget_caps(codec, fg);
-	if (err < 0) {
-		codec_err(codec, "cannot malloc\n");
+	if (err < 0)
 		return err;
-	}
 
 	snd_array_free(&codec->init_pins);
 	err = read_pin_defaults(codec);
@@ -1625,98 +1133,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets);
 
-
-#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
-/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
-static bool is_likely_hdmi_codec(struct hda_codec *codec)
-{
-	hda_nid_t nid = codec->start_nid;
-	int i;
-
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
-		unsigned int wcaps = get_wcaps(codec, nid);
-		switch (get_wcaps_type(wcaps)) {
-		case AC_WID_AUD_IN:
-			return false; /* HDMI parser supports only HDMI out */
-		case AC_WID_AUD_OUT:
-			if (!(wcaps & AC_WCAP_DIGITAL))
-				return false;
-			break;
-		}
-	}
-	return true;
-}
-#else
-/* no HDMI codec parser support */
-#define is_likely_hdmi_codec(codec)	false
-#endif /* CONFIG_SND_HDA_CODEC_HDMI */
-
-/**
- * snd_hda_codec_configure - (Re-)configure the HD-audio codec
- * @codec: the HDA codec
- *
- * Start parsing of the given codec tree and (re-)initialize the whole
- * patch instance.
- *
- * Returns 0 if successful or a negative error code.
- */
-int snd_hda_codec_configure(struct hda_codec *codec)
-{
-	int (*patch)(struct hda_codec *) = NULL;
-	int err;
-
-	codec->preset = find_codec_preset(codec);
-	if (!codec->vendor_name || !codec->chip_name) {
-		err = get_codec_name(codec);
-		if (err < 0)
-			return err;
-	}
-
-	if (!is_generic_config(codec) && codec->preset)
-		patch = codec->preset->patch;
-	if (!patch) {
-		unload_parser(codec); /* to be sure */
-		if (is_likely_hdmi_codec(codec)) {
-#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
-			patch = load_parser(codec, snd_hda_parse_hdmi_codec);
-#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI)
-			patch = snd_hda_parse_hdmi_codec;
-#endif
-		}
-		if (!patch) {
-#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
-			patch = load_parser(codec, snd_hda_parse_generic_codec);
-#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC)
-			patch = snd_hda_parse_generic_codec;
-#endif
-		}
-		if (!patch) {
-			codec_err(codec, "No codec parser is available\n");
-			return -ENODEV;
-		}
-	}
-
-	err = patch(codec);
-	if (err < 0) {
-		unload_parser(codec);
-		return err;
-	}
-
-	if (codec->patch_ops.unsol_event) {
-		err = init_unsol_queue(codec->bus);
-		if (err < 0)
-			return err;
-	}
-
-	/* audio codec should override the mixer name */
-	if (codec->afg || !*codec->bus->card->mixername)
-		snprintf(codec->bus->card->mixername,
-			 sizeof(codec->bus->card->mixername),
-			 "%s %s", codec->vendor_name, codec->chip_name);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
-
 /* update the stream-id if changed */
 static void update_pcm_stream_id(struct hda_codec *codec,
 				 struct hda_cvt_setup *p, hda_nid_t nid,
@@ -1782,6 +1198,8 @@
 	if (!p)
 		return;
 
+	if (codec->patch_ops.stream_pm)
+		codec->patch_ops.stream_pm(codec, nid, true);
 	if (codec->pcm_format_first)
 		update_pcm_format(codec, p, nid, format);
 	update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
@@ -1793,7 +1211,7 @@
 
 	/* make other inactive cvts with the same stream-tag dirty */
 	type = get_wcaps_type(get_wcaps(codec, nid));
-	list_for_each_entry(c, &codec->bus->codec_list, list) {
+	list_for_each_codec(c, codec->bus) {
 		for (i = 0; i < c->cvt_setups.used; i++) {
 			p = snd_array_elem(&c->cvt_setups, i);
 			if (!p->active && p->stream_tag == stream_tag &&
@@ -1850,6 +1268,8 @@
 );
 	memset(q, 0, sizeof(*q));
 	q->nid = nid;
+	if (codec->patch_ops.stream_pm)
+		codec->patch_ops.stream_pm(codec, nid, false);
 }
 
 /* clean up the all conflicting obsolete streams */
@@ -1858,7 +1278,7 @@
 	struct hda_codec *c;
 	int i;
 
-	list_for_each_entry(c, &codec->bus->codec_list, list) {
+	list_for_each_codec(c, codec->bus) {
 		for (i = 0; i < c->cvt_setups.used; i++) {
 			struct hda_cvt_setup *p;
 			p = snd_array_elem(&c->cvt_setups, i);
@@ -1886,127 +1306,6 @@
  * amp access functions
  */
 
-/* FIXME: more better hash key? */
-#define HDA_HASH_KEY(nid, dir, idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
-#define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
-#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
-#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
-#define INFO_AMP_CAPS	(1<<0)
-#define INFO_AMP_VOL(ch)	(1 << (1 + (ch)))
-
-/* initialize the hash table */
-static void init_hda_cache(struct hda_cache_rec *cache,
-				     unsigned int record_size)
-{
-	memset(cache, 0, sizeof(*cache));
-	memset(cache->hash, 0xff, sizeof(cache->hash));
-	snd_array_init(&cache->buf, record_size, 64);
-}
-
-static void free_hda_cache(struct hda_cache_rec *cache)
-{
-	snd_array_free(&cache->buf);
-}
-
-/* query the hash.  allocate an entry if not found. */
-static struct hda_cache_head  *get_hash(struct hda_cache_rec *cache, u32 key)
-{
-	u16 idx = key % (u16)ARRAY_SIZE(cache->hash);
-	u16 cur = cache->hash[idx];
-	struct hda_cache_head *info;
-
-	while (cur != 0xffff) {
-		info = snd_array_elem(&cache->buf, cur);
-		if (info->key == key)
-			return info;
-		cur = info->next;
-	}
-	return NULL;
-}
-
-/* query the hash.  allocate an entry if not found. */
-static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
-					      u32 key)
-{
-	struct hda_cache_head *info = get_hash(cache, key);
-	if (!info) {
-		u16 idx, cur;
-		/* add a new hash entry */
-		info = snd_array_new(&cache->buf);
-		if (!info)
-			return NULL;
-		cur = snd_array_index(&cache->buf, info);
-		info->key = key;
-		info->val = 0;
-		info->dirty = 0;
-		idx = key % (u16)ARRAY_SIZE(cache->hash);
-		info->next = cache->hash[idx];
-		cache->hash[idx] = cur;
-	}
-	return info;
-}
-
-/* query and allocate an amp hash entry */
-static inline struct hda_amp_info *
-get_alloc_amp_hash(struct hda_codec *codec, u32 key)
-{
-	return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
-}
-
-/* overwrite the value with the key in the caps hash */
-static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val)
-{
-	struct hda_amp_info *info;
-
-	mutex_lock(&codec->hash_mutex);
-	info = get_alloc_amp_hash(codec, key);
-	if (!info) {
-		mutex_unlock(&codec->hash_mutex);
-		return -EINVAL;
-	}
-	info->amp_caps = val;
-	info->head.val |= INFO_AMP_CAPS;
-	mutex_unlock(&codec->hash_mutex);
-	return 0;
-}
-
-/* query the value from the caps hash; if not found, fetch the current
- * value from the given function and store in the hash
- */
-static unsigned int
-query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key,
-		unsigned int (*func)(struct hda_codec *, hda_nid_t, int))
-{
-	struct hda_amp_info *info;
-	unsigned int val;
-
-	mutex_lock(&codec->hash_mutex);
-	info = get_alloc_amp_hash(codec, key);
-	if (!info) {
-		mutex_unlock(&codec->hash_mutex);
-		return 0;
-	}
-	if (!(info->head.val & INFO_AMP_CAPS)) {
-		mutex_unlock(&codec->hash_mutex); /* for reentrance */
-		val = func(codec, nid, dir);
-		write_caps_hash(codec, key, val);
-	} else {
-		val = info->amp_caps;
-		mutex_unlock(&codec->hash_mutex);
-	}
-	return val;
-}
-
-static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
-				 int direction)
-{
-	if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
-		nid = codec->afg;
-	return snd_hda_param_read(codec, nid,
-				  direction == HDA_OUTPUT ?
-				  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
-}
-
 /**
  * query_amp_caps - query AMP capabilities
  * @codec: the HD-auio codec
@@ -2021,9 +1320,11 @@
  */
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
-	return query_caps_hash(codec, nid, direction,
-			       HDA_HASH_KEY(nid, direction, 0),
-			       read_amp_cap);
+	if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
+		nid = codec->core.afg;
+	return snd_hda_param_read(codec, nid,
+				  direction == HDA_OUTPUT ?
+				  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
 }
 EXPORT_SYMBOL_GPL(query_amp_caps);
 
@@ -2064,184 +1365,15 @@
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps)
 {
-	return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps);
+	unsigned int parm;
+
+	snd_hda_override_wcaps(codec, nid,
+			       get_wcaps(codec, nid) | AC_WCAP_AMP_OVRD);
+	parm = dir == HDA_OUTPUT ? AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP;
+	return snd_hdac_override_parm(&codec->core, nid, parm, caps);
 }
 EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
 
-static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
-				 int dir)
-{
-	return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-}
-
-/**
- * snd_hda_query_pin_caps - Query PIN capabilities
- * @codec: the HD-auio codec
- * @nid: the NID to query
- *
- * Query PIN capabilities for the given widget.
- * Returns the obtained capability bits.
- *
- * When cap bits have been already read, this doesn't read again but
- * returns the cached value.
- */
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
-{
-	return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
-			       read_pin_cap);
-}
-EXPORT_SYMBOL_GPL(snd_hda_query_pin_caps);
-
-/**
- * snd_hda_override_pin_caps - Override the pin capabilities
- * @codec: the CODEC
- * @nid: the NID to override
- * @caps: the capability bits to set
- *
- * Override the cached PIN capabilitiy bits value by the given one.
- *
- * Returns zero if successful or a negative error code.
- */
-int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
-			      unsigned int caps)
-{
-	return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
-}
-EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps);
-
-/* read or sync the hash value with the current value;
- * call within hash_mutex
- */
-static struct hda_amp_info *
-update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
-		int direction, int index, bool init_only)
-{
-	struct hda_amp_info *info;
-	unsigned int parm, val = 0;
-	bool val_read = false;
-
- retry:
-	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
-	if (!info)
-		return NULL;
-	if (!(info->head.val & INFO_AMP_VOL(ch))) {
-		if (!val_read) {
-			mutex_unlock(&codec->hash_mutex);
-			parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
-			parm |= direction == HDA_OUTPUT ?
-				AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
-			parm |= index;
-			val = snd_hda_codec_read(codec, nid, 0,
-				 AC_VERB_GET_AMP_GAIN_MUTE, parm);
-			val &= 0xff;
-			val_read = true;
-			mutex_lock(&codec->hash_mutex);
-			goto retry;
-		}
-		info->vol[ch] = val;
-		info->head.val |= INFO_AMP_VOL(ch);
-	} else if (init_only)
-		return NULL;
-	return info;
-}
-
-/*
- * write the current volume in info to the h/w
- */
-static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps,
-			 hda_nid_t nid, int ch, int direction, int index,
-			 int val)
-{
-	u32 parm;
-
-	parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
-	parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
-	parm |= index << AC_AMP_SET_INDEX_SHIFT;
-	if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) &&
-	    (amp_caps & AC_AMPCAP_MIN_MUTE))
-		; /* set the zero value as a fake mute */
-	else
-		parm |= val;
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
-}
-
-/**
- * snd_hda_codec_amp_read - Read AMP value
- * @codec: HD-audio codec
- * @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @index: the index value (only for input direction)
- *
- * Read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
- */
-int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
-			   int direction, int index)
-{
-	struct hda_amp_info *info;
-	unsigned int val = 0;
-
-	mutex_lock(&codec->hash_mutex);
-	info = update_amp_hash(codec, nid, ch, direction, index, false);
-	if (info)
-		val = info->vol[ch];
-	mutex_unlock(&codec->hash_mutex);
-	return val;
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read);
-
-static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
-			    int direction, int idx, int mask, int val,
-			    bool init_only)
-{
-	struct hda_amp_info *info;
-	unsigned int caps;
-	unsigned int cache_only;
-
-	if (snd_BUG_ON(mask & ~0xff))
-		mask &= 0xff;
-	val &= mask;
-
-	mutex_lock(&codec->hash_mutex);
-	info = update_amp_hash(codec, nid, ch, direction, idx, init_only);
-	if (!info) {
-		mutex_unlock(&codec->hash_mutex);
-		return 0;
-	}
-	val |= info->vol[ch] & ~mask;
-	if (info->vol[ch] == val) {
-		mutex_unlock(&codec->hash_mutex);
-		return 0;
-	}
-	info->vol[ch] = val;
-	cache_only = info->head.dirty = codec->cached_write;
-	caps = info->amp_caps;
-	mutex_unlock(&codec->hash_mutex);
-	if (!cache_only)
-		put_vol_mute(codec, caps, nid, ch, direction, idx, val);
-	return 1;
-}
-
-/**
- * snd_hda_codec_amp_update - update the AMP value
- * @codec: HD-audio codec
- * @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @idx: the index value (only for input direction)
- * @mask: bit mask to set
- * @val: the bits value to set
- *
- * Update the AMP value with a bit mask.
- * Returns 0 if the value is unchanged, 1 if changed.
- */
-int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
-			     int direction, int idx, int mask, int val)
-{
-	return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
-
 /**
  * snd_hda_codec_amp_stereo - update the AMP stereo values
  * @codec: HD-audio codec
@@ -2285,7 +1417,16 @@
 int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
 			   int dir, int idx, int mask, int val)
 {
-	return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true);
+	int orig;
+
+	if (!codec->core.regmap)
+		return -EINVAL;
+	regcache_cache_only(codec->core.regmap, true);
+	orig = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
+	regcache_cache_only(codec->core.regmap, false);
+	if (orig >= 0)
+		return 0;
+	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
 
@@ -2314,49 +1455,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo);
 
-/**
- * snd_hda_codec_resume_amp - Resume all AMP commands from the cache
- * @codec: HD-audio codec
- *
- * Resume the all amp commands from the cache.
- */
-void snd_hda_codec_resume_amp(struct hda_codec *codec)
-{
-	int i;
-
-	mutex_lock(&codec->hash_mutex);
-	codec->cached_write = 0;
-	for (i = 0; i < codec->amp_cache.buf.used; i++) {
-		struct hda_amp_info *buffer;
-		u32 key;
-		hda_nid_t nid;
-		unsigned int idx, dir, ch;
-		struct hda_amp_info info;
-
-		buffer = snd_array_elem(&codec->amp_cache.buf, i);
-		if (!buffer->head.dirty)
-			continue;
-		buffer->head.dirty = 0;
-		info = *buffer;
-		key = info.head.key;
-		if (!key)
-			continue;
-		nid = key & 0xff;
-		idx = (key >> 16) & 0xff;
-		dir = (key >> 24) & 0xff;
-		for (ch = 0; ch < 2; ch++) {
-			if (!(info.head.val & INFO_AMP_VOL(ch)))
-				continue;
-			mutex_unlock(&codec->hash_mutex);
-			put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx,
-				     info.vol[ch]);
-			mutex_lock(&codec->hash_mutex);
-		}
-	}
-	mutex_unlock(&codec->hash_mutex);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp);
-
 static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
 			     unsigned int ofs)
 {
@@ -2478,14 +1576,12 @@
 	long *valp = ucontrol->value.integer.value;
 	int change = 0;
 
-	snd_hda_power_up(codec);
 	if (chs & 1) {
 		change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
 		valp++;
 	}
 	if (chs & 2)
 		change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
-	snd_hda_power_down(codec);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
@@ -2572,7 +1668,7 @@
 	if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
 		return NULL;
 	strcpy(id.name, name);
-	return snd_ctl_find_id(codec->bus->card, &id);
+	return snd_ctl_find_id(codec->card, &id);
 }
 
 /**
@@ -2636,7 +1732,7 @@
 		nid = kctl->id.subdevice & 0xffff;
 	if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
 		kctl->id.subdevice = 0;
-	err = snd_ctl_add(codec->bus->card, kctl);
+	err = snd_ctl_add(codec->card, kctl);
 	if (err < 0)
 		return err;
 	item = snd_array_new(&codec->mixers);
@@ -2689,7 +1785,7 @@
 	int i;
 	struct hda_nid_item *items = codec->mixers.list;
 	for (i = 0; i < codec->mixers.used; i++)
-		snd_ctl_remove(codec->bus->card, items[i].kctl);
+		snd_ctl_remove(codec->card, items[i].kctl);
 	snd_array_free(&codec->mixers);
 	snd_array_free(&codec->nids);
 }
@@ -2712,10 +1808,9 @@
 	if (!list_empty(&card->ctl_files))
 		goto err_clear;
 
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		int pcm;
-		for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-			struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+	list_for_each_codec(codec, bus) {
+		struct hda_pcm *cpcm;
+		list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
 			if (!cpcm->pcm)
 				continue;
 			if (cpcm->pcm->streams[0].substream_opened ||
@@ -2742,7 +1837,6 @@
 {
 	struct snd_card *card = bus->card;
 
-	card = bus->card;
 	spin_lock(&card->files_lock);
 	card->shutdown = 0;
 	spin_unlock(&card->files_lock);
@@ -2762,51 +1856,12 @@
 int snd_hda_codec_reset(struct hda_codec *codec)
 {
 	struct hda_bus *bus = codec->bus;
-	struct snd_card *card = bus->card;
-	int i;
 
 	if (snd_hda_lock_devices(bus) < 0)
 		return -EBUSY;
 
 	/* OK, let it free */
-	cancel_delayed_work_sync(&codec->jackpoll_work);
-#ifdef CONFIG_PM
-	cancel_delayed_work_sync(&codec->power_work);
-	flush_workqueue(bus->workq);
-#endif
-	snd_hda_ctls_clear(codec);
-	/* release PCMs */
-	for (i = 0; i < codec->num_pcms; i++) {
-		if (codec->pcm_info[i].pcm) {
-			snd_device_free(card, codec->pcm_info[i].pcm);
-			clear_bit(codec->pcm_info[i].device,
-				  bus->pcm_dev_bits);
-		}
-	}
-	snd_hda_detach_beep_device(codec);
-	if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
-	memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
-	snd_hda_jack_tbl_clear(codec);
-	codec->proc_widget_hook = NULL;
-	codec->spec = NULL;
-	free_hda_cache(&codec->amp_cache);
-	free_hda_cache(&codec->cmd_cache);
-	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
-	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
-	/* free only driver_pins so that init_pins + user_pins are restored */
-	snd_array_free(&codec->driver_pins);
-	snd_array_free(&codec->cvt_setups);
-	snd_array_free(&codec->spdif_out);
-	snd_array_free(&codec->verbs);
-	codec->num_pcms = 0;
-	codec->pcm_info = NULL;
-	codec->preset = NULL;
-	codec->slave_dig_outs = NULL;
-	codec->spdif_status_reset = 0;
-	unload_parser(codec);
-	module_put(codec->owner);
-	codec->owner = NULL;
+	snd_hdac_device_unregister(&codec->core);
 
 	/* allow device access again */
 	snd_hda_unlock_devices(bus);
@@ -3153,7 +2208,6 @@
 	long *valp = ucontrol->value.integer.value;
 	int change = 0;
 
-	snd_hda_power_up(codec);
 	if (chs & 1) {
 		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
 						  HDA_AMP_MUTE,
@@ -3165,7 +2219,6 @@
 						   HDA_AMP_MUTE,
 						   *valp ? 0 : HDA_AMP_MUTE);
 	hda_call_check_power_status(codec, nid);
-	snd_hda_power_down(codec);
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
@@ -3466,25 +2519,35 @@
 
 /* set digital convert verbs both for the given NID and its slaves */
 static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
-			int verb, int val)
+			int mask, int val)
 {
 	const hda_nid_t *d;
 
-	snd_hda_codec_write_cache(codec, nid, 0, verb, val);
+	snd_hdac_regmap_update(&codec->core, nid, AC_VERB_SET_DIGI_CONVERT_1,
+			       mask, val);
 	d = codec->slave_dig_outs;
 	if (!d)
 		return;
 	for (; *d; d++)
-		snd_hda_codec_write_cache(codec, *d, 0, verb, val);
+		snd_hdac_regmap_update(&codec->core, nid,
+				       AC_VERB_SET_DIGI_CONVERT_1, mask, val);
 }
 
 static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
 				       int dig1, int dig2)
 {
-	if (dig1 != -1)
-		set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
-	if (dig2 != -1)
-		set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
+	unsigned int mask = 0;
+	unsigned int val = 0;
+
+	if (dig1 != -1) {
+		mask |= 0xff;
+		val = dig1;
+	}
+	if (dig2 != -1) {
+		mask |= 0xff00;
+		val |= dig2 << 8;
+	}
+	set_dig_out(codec, nid, mask, val);
 }
 
 static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
@@ -3617,6 +2680,7 @@
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol_new *dig_mix;
 	int idx = 0;
+	int val = 0;
 	const int spdif_index = 16;
 	struct hda_spdif_out *spdif;
 	struct hda_bus *bus = codec->bus;
@@ -3657,8 +2721,9 @@
 			return err;
 	}
 	spdif->nid = cvt_nid;
-	spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0,
-					 AC_VERB_GET_DIGI_CONVERT_1, 0);
+	snd_hdac_regmap_read(&codec->core, cvt_nid,
+			     AC_VERB_GET_DIGI_CONVERT_1, &val);
+	spdif->ctls = val;
 	spdif->status = convert_to_spdif_status(spdif->ctls);
 	return 0;
 }
@@ -3802,8 +2867,8 @@
 	change = codec->spdif_in_enable != val;
 	if (change) {
 		codec->spdif_in_enable = val;
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_DIGI_CONVERT_1, val);
+		snd_hdac_regmap_write(&codec->core, nid,
+				      AC_VERB_SET_DIGI_CONVERT_1, val);
 	}
 	mutex_unlock(&codec->spdif_mutex);
 	return change;
@@ -3814,10 +2879,11 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	hda_nid_t nid = kcontrol->private_value;
-	unsigned short val;
+	unsigned int val;
 	unsigned int sbits;
 
-	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
+	snd_hdac_regmap_read(&codec->core, nid,
+			     AC_VERB_GET_DIGI_CONVERT_1, &val);
 	sbits = convert_to_spdif_status(val);
 	ucontrol->value.iec958.status[0] = sbits;
 	ucontrol->value.iec958.status[1] = sbits >> 8;
@@ -3883,153 +2949,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls);
 
-/*
- * command cache
- */
-
-/* build a 31bit cache key with the widget id and the command parameter */
-#define build_cmd_cache_key(nid, verb)	((verb << 8) | nid)
-#define get_cmd_cache_nid(key)		((key) & 0xff)
-#define get_cmd_cache_cmd(key)		(((key) >> 8) & 0xffff)
-
-/**
- * snd_hda_codec_write_cache - send a single command with caching
- * @codec: the HDA codec
- * @nid: NID to send the command
- * @flags: optional bit flags
- * @verb: the verb to send
- * @parm: the parameter for the verb
- *
- * Send a single command without waiting for response.
- *
- * Returns 0 if successful, or a negative error code.
- */
-int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
-			      int flags, unsigned int verb, unsigned int parm)
-{
-	int err;
-	struct hda_cache_head *c;
-	u32 key;
-	unsigned int cache_only;
-
-	cache_only = codec->cached_write;
-	if (!cache_only) {
-		err = snd_hda_codec_write(codec, nid, flags, verb, parm);
-		if (err < 0)
-			return err;
-	}
-
-	/* parm may contain the verb stuff for get/set amp */
-	verb = verb | (parm >> 8);
-	parm &= 0xff;
-	key = build_cmd_cache_key(nid, verb);
-	mutex_lock(&codec->bus->cmd_mutex);
-	c = get_alloc_hash(&codec->cmd_cache, key);
-	if (c) {
-		c->val = parm;
-		c->dirty = cache_only;
-	}
-	mutex_unlock(&codec->bus->cmd_mutex);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache);
-
-/**
- * snd_hda_codec_update_cache - check cache and write the cmd only when needed
- * @codec: the HDA codec
- * @nid: NID to send the command
- * @flags: optional bit flags
- * @verb: the verb to send
- * @parm: the parameter for the verb
- *
- * This function works like snd_hda_codec_write_cache(), but it doesn't send
- * command if the parameter is already identical with the cached value.
- * If not, it sends the command and refreshes the cache.
- *
- * Returns 0 if successful, or a negative error code.
- */
-int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
-			       int flags, unsigned int verb, unsigned int parm)
-{
-	struct hda_cache_head *c;
-	u32 key;
-
-	/* parm may contain the verb stuff for get/set amp */
-	verb = verb | (parm >> 8);
-	parm &= 0xff;
-	key = build_cmd_cache_key(nid, verb);
-	mutex_lock(&codec->bus->cmd_mutex);
-	c = get_hash(&codec->cmd_cache, key);
-	if (c && c->val == parm) {
-		mutex_unlock(&codec->bus->cmd_mutex);
-		return 0;
-	}
-	mutex_unlock(&codec->bus->cmd_mutex);
-	return snd_hda_codec_write_cache(codec, nid, flags, verb, parm);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_update_cache);
-
-/**
- * snd_hda_codec_resume_cache - Resume the all commands from the cache
- * @codec: HD-audio codec
- *
- * Execute all verbs recorded in the command caches to resume.
- */
-void snd_hda_codec_resume_cache(struct hda_codec *codec)
-{
-	int i;
-
-	mutex_lock(&codec->hash_mutex);
-	codec->cached_write = 0;
-	for (i = 0; i < codec->cmd_cache.buf.used; i++) {
-		struct hda_cache_head *buffer;
-		u32 key;
-
-		buffer = snd_array_elem(&codec->cmd_cache.buf, i);
-		key = buffer->key;
-		if (!key)
-			continue;
-		if (!buffer->dirty)
-			continue;
-		buffer->dirty = 0;
-		mutex_unlock(&codec->hash_mutex);
-		snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0,
-				    get_cmd_cache_cmd(key), buffer->val);
-		mutex_lock(&codec->hash_mutex);
-	}
-	mutex_unlock(&codec->hash_mutex);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache);
-
-/**
- * snd_hda_sequence_write_cache - sequence writes with caching
- * @codec: the HDA codec
- * @seq: VERB array to send
- *
- * Send the commands sequentially from the given array.
- * Thte commands are recorded on cache for power-save and resume.
- * The array must be terminated with NID=0.
- */
-void snd_hda_sequence_write_cache(struct hda_codec *codec,
-				  const struct hda_verb *seq)
-{
-	for (; seq->nid; seq++)
-		snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb,
-					  seq->param);
-}
-EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache);
-
-/**
- * snd_hda_codec_flush_cache - Execute all pending (cached) amps / verbs
- * @codec: HD-audio codec
- */
-void snd_hda_codec_flush_cache(struct hda_codec *codec)
-{
-	snd_hda_codec_resume_amp(codec);
-	snd_hda_codec_resume_cache(codec);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache);
-
 /**
  * snd_hda_codec_set_power_to_all - Set the power state to all widgets
  * @codec: the HDA codec
@@ -4043,10 +2962,9 @@
 void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
 				    unsigned int power_state)
 {
-	hda_nid_t nid = codec->start_nid;
-	int i;
+	hda_nid_t nid;
 
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		unsigned int wcaps = get_wcaps(codec, nid);
 		unsigned int state = power_state;
 		if (!(wcaps & AC_WCAP_POWER))
@@ -4063,22 +2981,6 @@
 EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all);
 
 /*
- *  supported power states check
- */
-static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg,
-				unsigned int power_state)
-{
-	int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE);
-
-	if (sup == -1)
-		return false;
-	if (sup & power_state)
-		return true;
-	else
-		return false;
-}
-
-/*
  * wait until the state is reached, returns the current state
  */
 static unsigned int hda_sync_power_state(struct hda_codec *codec,
@@ -4117,7 +3019,7 @@
 					     hda_nid_t nid,
 					     unsigned int power_state)
 {
-	if (nid == codec->afg || nid == codec->mfg)
+	if (nid == codec->core.afg || nid == codec->core.mfg)
 		return power_state;
 	if (power_state == AC_PWRST_D3 &&
 	    get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
@@ -4137,7 +3039,7 @@
 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;
+	hda_nid_t fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
 	int count;
 	unsigned int state;
 	int flags = 0;
@@ -4145,7 +3047,7 @@
 	/* this delay seems necessary to avoid click noise at power-down */
 	if (power_state == AC_PWRST_D3) {
 		if (codec->depop_delay < 0)
-			msleep(codec->epss ? 10 : 100);
+			msleep(codec_has_epss(codec) ? 10 : 100);
 		else if (codec->depop_delay > 0)
 			msleep(codec->depop_delay);
 		flags = HDA_RW_NO_RESPONSE_FALLBACK;
@@ -4179,14 +3081,13 @@
  */
 static void sync_power_up_states(struct hda_codec *codec)
 {
-	hda_nid_t nid = codec->start_nid;
-	int i;
+	hda_nid_t nid;
 
 	/* don't care if no filter is used */
 	if (!codec->power_filter)
 		return;
 
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		unsigned int wcaps = get_wcaps(codec, nid);
 		unsigned int target;
 		if (!(wcaps & AC_WCAP_POWER))
@@ -4212,63 +3113,54 @@
 #endif
 
 #ifdef CONFIG_PM
+/* update the power on/off account with the current jiffies */
+static void update_power_acct(struct hda_codec *codec, bool on)
+{
+	unsigned long delta = jiffies - codec->power_jiffies;
+
+	if (on)
+		codec->power_on_acct += delta;
+	else
+		codec->power_off_acct += delta;
+	codec->power_jiffies += delta;
+}
+
+void snd_hda_update_power_acct(struct hda_codec *codec)
+{
+	update_power_acct(codec, hda_codec_is_power_on(codec));
+}
+
 /*
  * call suspend and power-down; used both from PM and power-save
  * this function returns the power state in the end
  */
-static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
+static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
 {
 	unsigned int state;
 
-	codec->in_pm = 1;
+	atomic_inc(&codec->core.in_pm);
 
 	if (codec->patch_ops.suspend)
 		codec->patch_ops.suspend(codec);
 	hda_cleanup_all_streams(codec);
 	state = hda_set_power_state(codec, AC_PWRST_D3);
-	/* Cancel delayed work if we aren't currently running from it. */
-	if (!in_wq)
-		cancel_delayed_work_sync(&codec->power_work);
-	spin_lock(&codec->power_lock);
-	snd_hda_update_power_acct(codec);
-	trace_hda_power_down(codec);
-	codec->power_on = 0;
-	codec->power_transition = 0;
-	codec->power_jiffies = jiffies;
-	spin_unlock(&codec->power_lock);
-	codec->in_pm = 0;
+	update_power_acct(codec, true);
+	atomic_dec(&codec->core.in_pm);
 	return state;
 }
 
-/* mark all entries of cmd and amp caches dirty */
-static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
-{
-	int i;
-	for (i = 0; i < codec->cmd_cache.buf.used; i++) {
-		struct hda_cache_head *cmd;
-		cmd = snd_array_elem(&codec->cmd_cache.buf, i);
-		cmd->dirty = 1;
-	}
-	for (i = 0; i < codec->amp_cache.buf.used; i++) {
-		struct hda_amp_info *amp;
-		amp = snd_array_elem(&codec->amp_cache.buf, i);
-		amp->head.dirty = 1;
-	}
-}
-
 /*
  * kick up codec; used both from PM and power-save
  */
 static void hda_call_codec_resume(struct hda_codec *codec)
 {
-	codec->in_pm = 1;
+	atomic_inc(&codec->core.in_pm);
 
-	hda_mark_cmd_cache_dirty(codec);
+	if (codec->core.regmap)
+		regcache_mark_dirty(codec->core.regmap);
 
-	/* set as if powered on for avoiding re-entering the resume
-	 * in the resume / power-save sequence
-	 */
-	hda_keep_power_on(codec);
+	codec->power_jiffies = jiffies;
+
 	hda_set_power_state(codec, AC_PWRST_D0);
 	restore_shutup_pins(codec);
 	hda_exec_init_verbs(codec);
@@ -4278,72 +3170,71 @@
 	else {
 		if (codec->patch_ops.init)
 			codec->patch_ops.init(codec);
-		snd_hda_codec_resume_amp(codec);
-		snd_hda_codec_resume_cache(codec);
+		if (codec->core.regmap)
+			regcache_sync(codec->core.regmap);
 	}
 
 	if (codec->jackpoll_interval)
 		hda_jackpoll_work(&codec->jackpoll_work.work);
 	else
 		snd_hda_jack_report_sync(codec);
+	atomic_dec(&codec->core.in_pm);
+}
 
-	codec->in_pm = 0;
-	snd_hda_power_down(codec); /* flag down before returning */
+static int hda_codec_runtime_suspend(struct device *dev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(dev);
+	struct hda_pcm *pcm;
+	unsigned int state;
+
+	cancel_delayed_work_sync(&codec->jackpoll_work);
+	list_for_each_entry(pcm, &codec->pcm_list_head, list)
+		snd_pcm_suspend_all(pcm->pcm);
+	state = hda_call_codec_suspend(codec);
+	if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
+	    (state & AC_PWRST_CLK_STOP_OK))
+		snd_hdac_codec_link_down(&codec->core);
+	return 0;
+}
+
+static int hda_codec_runtime_resume(struct device *dev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(dev);
+
+	snd_hdac_codec_link_up(&codec->core);
+	hda_call_codec_resume(codec);
+	pm_runtime_mark_last_busy(dev);
+	return 0;
 }
 #endif /* CONFIG_PM */
 
-
-/**
- * snd_hda_build_controls - build mixer controls
- * @bus: the BUS
- *
- * Creates mixer controls for each codec included in the bus.
- *
- * Returns 0 if successful, otherwise a negative error code.
- */
-int snd_hda_build_controls(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
-
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		int err = snd_hda_codec_build_controls(codec);
-		if (err < 0) {
-			codec_err(codec,
-				  "cannot build controls for #%d (error %d)\n",
-				  codec->addr, err);
-			err = snd_hda_codec_reset(codec);
-			if (err < 0) {
-				codec_err(codec,
-					  "cannot revert codec\n");
-				return err;
-			}
-		}
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_build_controls);
+/* referred in hda_bind.c */
+const struct dev_pm_ops hda_codec_driver_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume,
+			   NULL)
+};
 
 /*
  * add standard channel maps if not specified
  */
 static int add_std_chmaps(struct hda_codec *codec)
 {
-	int i, str, err;
+	struct hda_pcm *pcm;
+	int str, err;
 
-	for (i = 0; i < codec->num_pcms; i++) {
+	list_for_each_entry(pcm, &codec->pcm_list_head, list) {
 		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 hda_pcm_stream *hinfo = &pcm->stream[str];
 			struct snd_pcm_chmap *chmap;
 			const struct snd_pcm_chmap_elem *elem;
 
-			if (codec->pcm_info[i].own_chmap)
-				continue;
-			if (!pcm || !hinfo->substreams)
+			if (!pcm || pcm->own_chmap ||
+			    !hinfo->substreams)
 				continue;
 			elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps;
-			err = snd_pcm_add_chmap_ctls(pcm, str, elem,
+			err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem,
 						     hinfo->channels_max,
 						     0, &chmap);
 			if (err < 0)
@@ -4499,43 +3390,29 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format);
 
-static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
-				  int dir)
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
 {
 	unsigned int val = 0;
-	if (nid != codec->afg &&
+	if (nid != codec->core.afg &&
 	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
 		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
 	if (!val || val == -1)
-		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+		val = snd_hda_param_read(codec, codec->core.afg, AC_PAR_PCM);
 	if (!val || val == -1)
 		return 0;
 	return val;
 }
 
-static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
-{
-	return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid),
-			       get_pcm_param);
-}
-
-static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
-				     int dir)
+static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
 {
 	unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
 	if (!streams || streams == -1)
-		streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+		streams = snd_hda_param_read(codec, codec->core.afg, AC_PAR_STREAM);
 	if (!streams || streams == -1)
 		return 0;
 	return streams;
 }
 
-static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
-{
-	return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid),
-			       get_stream_param);
-}
-
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
  * @codec: the HDA codec
@@ -4792,7 +3669,11 @@
 {
 	int ret;
 	mutex_lock(&codec->bus->prepare_mutex);
-	ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream);
+	if (hinfo->ops.prepare)
+		ret = hinfo->ops.prepare(hinfo, codec, stream, format,
+					 substream);
+	else
+		ret = -ENODEV;
 	if (ret >= 0)
 		purify_inactive_streams(codec);
 	mutex_unlock(&codec->bus->prepare_mutex);
@@ -4813,7 +3694,8 @@
 			   struct snd_pcm_substream *substream)
 {
 	mutex_lock(&codec->bus->prepare_mutex);
-	hinfo->ops.cleanup(hinfo, codec, substream);
+	if (hinfo->ops.cleanup)
+		hinfo->ops.cleanup(hinfo, codec, substream);
 	mutex_unlock(&codec->bus->prepare_mutex);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
@@ -4871,114 +3753,86 @@
 	return -EAGAIN;
 }
 
-/*
- * attach a new PCM stream
- */
-static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
+/* call build_pcms ops of the given codec and set up the default parameters */
+int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 {
-	struct hda_bus *bus = codec->bus;
-	struct hda_pcm_stream *info;
-	int stream, err;
+	struct hda_pcm *cpcm;
+	int err;
 
-	if (snd_BUG_ON(!pcm->name))
-		return -EINVAL;
-	for (stream = 0; stream < 2; stream++) {
-		info = &pcm->stream[stream];
-		if (info->substreams) {
+	if (!list_empty(&codec->pcm_list_head))
+		return 0; /* already parsed */
+
+	if (!codec->patch_ops.build_pcms)
+		return 0;
+
+	err = codec->patch_ops.build_pcms(codec);
+	if (err < 0) {
+		codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
+			  codec->core.addr, err);
+		return err;
+	}
+
+	list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
+		int stream;
+
+		for (stream = 0; stream < 2; stream++) {
+			struct hda_pcm_stream *info = &cpcm->stream[stream];
+
+			if (!info->substreams)
+				continue;
 			err = set_pcm_default_values(codec, info);
-			if (err < 0)
+			if (err < 0) {
+				codec_warn(codec,
+					   "fail to setup default for PCM %s\n",
+					   cpcm->name);
 				return err;
+			}
 		}
 	}
-	return bus->ops.attach_pcm(bus, codec, pcm);
+
+	return 0;
 }
 
 /* assign all PCMs of the given codec */
 int snd_hda_codec_build_pcms(struct hda_codec *codec)
 {
-	unsigned int pcm;
-	int err;
+	struct hda_bus *bus = codec->bus;
+	struct hda_pcm *cpcm;
+	int dev, err;
 
-	if (!codec->num_pcms) {
-		if (!codec->patch_ops.build_pcms)
-			return 0;
-		err = codec->patch_ops.build_pcms(codec);
-		if (err < 0) {
-			codec_err(codec,
-				  "cannot build PCMs for #%d (error %d)\n",
-				  codec->addr, err);
-			err = snd_hda_codec_reset(codec);
-			if (err < 0) {
-				codec_err(codec,
-					  "cannot revert codec\n");
-				return err;
-			}
-		}
+	if (snd_BUG_ON(!bus->ops.attach_pcm))
+		return -EINVAL;
+
+	err = snd_hda_codec_parse_pcms(codec);
+	if (err < 0) {
+		snd_hda_codec_reset(codec);
+		return err;
 	}
-	for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-		struct hda_pcm *cpcm = &codec->pcm_info[pcm];
-		int dev;
 
+	/* attach a new PCM streams */
+	list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
+		if (cpcm->pcm)
+			continue; /* already attached */
 		if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
 			continue; /* no substreams assigned */
 
-		if (!cpcm->pcm) {
-			dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
-			if (dev < 0)
-				continue; /* no fatal error */
-			cpcm->device = dev;
-			err = snd_hda_attach_pcm(codec, cpcm);
-			if (err < 0) {
-				codec_err(codec,
-					  "cannot attach PCM stream %d for codec #%d\n",
-					  dev, codec->addr);
-				continue; /* no fatal error */
-			}
+		dev = get_empty_pcm_device(bus, cpcm->pcm_type);
+		if (dev < 0)
+			continue; /* no fatal error */
+		cpcm->device = dev;
+		err =  bus->ops.attach_pcm(bus, codec, cpcm);
+		if (err < 0) {
+			codec_err(codec,
+				  "cannot attach PCM stream %d for codec #%d\n",
+				  dev, codec->core.addr);
+			continue; /* no fatal error */
 		}
 	}
+
 	return 0;
 }
 
 /**
- * snd_hda_build_pcms - build PCM information
- * @bus: the BUS
- *
- * Create PCM information for each codec included in the bus.
- *
- * The build_pcms codec patch is requested to set up codec->num_pcms and
- * codec->pcm_info properly.  The array is referred by the top-level driver
- * to create its PCM instances.
- * The allocated codec->pcm_info should be released in codec->patch_ops.free
- * callback.
- *
- * At least, substreams, channels_min and channels_max must be filled for
- * each stream.  substreams = 0 indicates that the stream doesn't exist.
- * When rates and/or formats are zero, the supported values are queried
- * from the given nid.  The nid is used also by the default ops.prepare
- * and ops.cleanup callbacks.
- *
- * The driver needs to call ops.open in its open callback.  Similarly,
- * ops.close is supposed to be called in the close callback.
- * ops.prepare should be called in the prepare or hw_params callback
- * with the proper parameters for set up.
- * ops.cleanup should be called in hw_free for clean up of streams.
- *
- * This function returns 0 if successful, or a negative error code.
- */
-int snd_hda_build_pcms(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
-
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		int err = snd_hda_codec_build_pcms(codec);
-		if (err < 0)
-			return err;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
-
-/**
  * snd_hda_add_new_ctls - create controls from the array
  * @codec: the HDA codec
  * @knew: the array of struct snd_kcontrol_new
@@ -5013,8 +3867,8 @@
 			 * the codec addr; if it still fails (or it's the
 			 * primary codec), then try another control index
 			 */
-			if (!addr && codec->addr)
-				addr = codec->addr;
+			if (!addr && codec->core.addr)
+				addr = codec->core.addr;
 			else if (!idx && !knew->index) {
 				idx = find_empty_mixer_ctl_idx(codec,
 							       knew->name, 0);
@@ -5029,127 +3883,37 @@
 EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
 
 #ifdef CONFIG_PM
-static void hda_power_work(struct work_struct *work)
+static void codec_set_power_save(struct hda_codec *codec, int delay)
 {
-	struct hda_codec *codec =
-		container_of(work, struct hda_codec, power_work.work);
-	struct hda_bus *bus = codec->bus;
-	unsigned int state;
+	struct device *dev = hda_codec_dev(codec);
 
-	spin_lock(&codec->power_lock);
-	if (codec->power_transition > 0) { /* during power-up sequence? */
-		spin_unlock(&codec->power_lock);
-		return;
-	}
-	if (!codec->power_on || codec->power_count) {
-		codec->power_transition = 0;
-		spin_unlock(&codec->power_lock);
-		return;
-	}
-	spin_unlock(&codec->power_lock);
-
-	state = hda_call_codec_suspend(codec, true);
-	if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK))
-		hda_call_pm_notify(codec, false);
-}
-
-static void hda_keep_power_on(struct hda_codec *codec)
-{
-	spin_lock(&codec->power_lock);
-	codec->power_count++;
-	codec->power_on = 1;
-	codec->power_jiffies = jiffies;
-	spin_unlock(&codec->power_lock);
-	hda_call_pm_notify(codec, true);
-}
-
-/* update the power on/off account with the current jiffies */
-void snd_hda_update_power_acct(struct hda_codec *codec)
-{
-	unsigned long delta = jiffies - codec->power_jiffies;
-	if (codec->power_on)
-		codec->power_on_acct += delta;
-	else
-		codec->power_off_acct += delta;
-	codec->power_jiffies += delta;
-}
-
-/* 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)
-{
-	/* 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))
-		return;
-	spin_unlock(&codec->power_lock);
-
-	cancel_delayed_work_sync(&codec->power_work);
-
-	spin_lock(&codec->power_lock);
-	/* If the power down delayed work was cancelled above before starting,
-	 * then there is no need to go through power up here.
-	 */
-	if (codec->power_on) {
-		if (codec->power_transition < 0)
-			codec->power_transition = 0;
-		return;
-	}
-
-	trace_hda_power_up(codec);
-	snd_hda_update_power_acct(codec);
-	codec->power_on = 1;
-	codec->power_jiffies = jiffies;
-	codec->power_transition = 1; /* avoid reentrance */
-	spin_unlock(&codec->power_lock);
-
-	hda_call_codec_resume(codec);
-
-	spin_lock(&codec->power_lock);
-	codec->power_transition = 0;
-}
-
-#define power_save(codec)	\
-	((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
-
-/* Transition to powered down */
-static void __snd_hda_power_down(struct hda_codec *codec)
-{
-	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));
+	if (delay > 0) {
+		pm_runtime_set_autosuspend_delay(dev, delay);
+		pm_runtime_use_autosuspend(dev);
+		pm_runtime_allow(dev);
+		if (!pm_runtime_suspended(dev))
+			pm_runtime_mark_last_busy(dev);
+	} else {
+		pm_runtime_dont_use_autosuspend(dev);
+		pm_runtime_forbid(dev);
 	}
 }
 
 /**
- * snd_hda_power_save - Power-up/down/sync the codec
- * @codec: HD-audio codec
- * @delta: the counter delta to change
- * @d3wait: sync for D3 transition complete
+ * snd_hda_set_power_save - reprogram autosuspend for the given delay
+ * @bus: HD-audio bus
+ * @delay: autosuspend delay in msec, 0 = off
  *
- * 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.
+ * Synchronize the runtime PM autosuspend state from the power_save option.
  */
-void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
+void snd_hda_set_power_save(struct hda_bus *bus, int delay)
 {
-	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);
+	struct hda_codec *c;
+
+	list_for_each_codec(c, bus)
+		codec_set_power_save(c, delay);
 }
-EXPORT_SYMBOL_GPL(snd_hda_power_save);
+EXPORT_SYMBOL_GPL(snd_hda_set_power_save);
 
 /**
  * snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5187,7 +3951,7 @@
 			if (!(v & HDA_AMP_MUTE) && v > 0) {
 				if (!check->power_on) {
 					check->power_on = 1;
-					snd_hda_power_up(codec);
+					snd_hda_power_up_pm(codec);
 				}
 				return 1;
 			}
@@ -5195,7 +3959,7 @@
 	}
 	if (check->power_on) {
 		check->power_on = 0;
-		snd_hda_power_down(codec);
+		snd_hda_power_down_pm(codec);
 	}
 	return 0;
 }
@@ -5203,88 +3967,6 @@
 #endif
 
 /*
- * Channel mode helper
- */
-
-/**
- * snd_hda_ch_mode_info - Info callback helper for the channel mode enum
- * @codec: the HDA codec
- * @uinfo: pointer to get/store the data
- * @chmode: channel mode array
- * @num_chmodes: channel mode array size
- */
-int snd_hda_ch_mode_info(struct hda_codec *codec,
-			 struct snd_ctl_elem_info *uinfo,
-			 const struct hda_channel_mode *chmode,
-			 int num_chmodes)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = num_chmodes;
-	if (uinfo->value.enumerated.item >= num_chmodes)
-		uinfo->value.enumerated.item = num_chmodes - 1;
-	sprintf(uinfo->value.enumerated.name, "%dch",
-		chmode[uinfo->value.enumerated.item].channels);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
-
-/**
- * snd_hda_ch_mode_get - Get callback helper for the channel mode enum
- * @codec: the HDA codec
- * @ucontrol: pointer to get/store the data
- * @chmode: channel mode array
- * @num_chmodes: channel mode array size
- * @max_channels: max number of channels
- */
-int snd_hda_ch_mode_get(struct hda_codec *codec,
-			struct snd_ctl_elem_value *ucontrol,
-			const struct hda_channel_mode *chmode,
-			int num_chmodes,
-			int max_channels)
-{
-	int i;
-
-	for (i = 0; i < num_chmodes; i++) {
-		if (max_channels == chmode[i].channels) {
-			ucontrol->value.enumerated.item[0] = i;
-			break;
-		}
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
-
-/**
- * snd_hda_ch_mode_put - Put callback helper for the channel mode enum
- * @codec: the HDA codec
- * @ucontrol: pointer to get/store the data
- * @chmode: channel mode array
- * @num_chmodes: channel mode array size
- * @max_channelsp: pointer to store the max channels
- */
-int snd_hda_ch_mode_put(struct hda_codec *codec,
-			struct snd_ctl_elem_value *ucontrol,
-			const struct hda_channel_mode *chmode,
-			int num_chmodes,
-			int *max_channelsp)
-{
-	unsigned int mode;
-
-	mode = ucontrol->value.enumerated.item[0];
-	if (mode >= num_chmodes)
-		return -EINVAL;
-	if (*max_channelsp == chmode[mode].channels)
-		return 0;
-	/* change the current channel setting */
-	*max_channelsp = chmode[mode].channels;
-	if (chmode[mode].sequence)
-		snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
-	return 1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
-
-/*
  * input MUX helper
  */
 
@@ -5418,24 +4100,6 @@
 }
 
 /**
- * snd_hda_bus_reboot_notify - call the reboot notifier of each codec
- * @bus: HD-audio bus
- */
-void snd_hda_bus_reboot_notify(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
-
-	if (!bus)
-		return;
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		if (hda_codec_is_power_on(codec) &&
-		    codec->patch_ops.reboot_notify)
-			codec->patch_ops.reboot_notify(codec);
-	}
-}
-EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify);
-
-/**
  * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
  * @codec: the HDA codec
  * @mout: hda_multi_out object
@@ -5825,123 +4489,26 @@
 }
 EXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
 
-
-#ifdef CONFIG_PM
-/*
- * power management
- */
-
-
-static void hda_async_suspend(void *data, async_cookie_t cookie)
-{
-	hda_call_codec_suspend(data, false);
-}
-
-static void hda_async_resume(void *data, async_cookie_t cookie)
-{
-	hda_call_codec_resume(data);
-}
-
 /**
- * snd_hda_suspend - suspend the codecs
- * @bus: the HDA bus
- *
- * Returns 0 if successful.
+ * snd_hda_bus_reset - Reset the bus
+ * @bus: HD-audio bus
  */
-int snd_hda_suspend(struct hda_bus *bus)
+void snd_hda_bus_reset(struct hda_bus *bus)
 {
 	struct hda_codec *codec;
-	ASYNC_DOMAIN_EXCLUSIVE(domain);
 
-	list_for_each_entry(codec, &bus->codec_list, list) {
+	list_for_each_codec(codec, bus) {
+		/* FIXME: maybe a better way needed for forced reset */
 		cancel_delayed_work_sync(&codec->jackpoll_work);
+#ifdef CONFIG_PM
 		if (hda_codec_is_power_on(codec)) {
-			if (bus->num_codecs > 1)
-				async_schedule_domain(hda_async_suspend, codec,
-						      &domain);
-			else
-				hda_call_codec_suspend(codec, false);
-		}
-	}
-
-	if (bus->num_codecs > 1)
-		async_synchronize_full_domain(&domain);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_suspend);
-
-/**
- * snd_hda_resume - resume the codecs
- * @bus: the HDA bus
- *
- * Returns 0 if successful.
- */
-int snd_hda_resume(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
-	ASYNC_DOMAIN_EXCLUSIVE(domain);
-
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		if (bus->num_codecs > 1)
-			async_schedule_domain(hda_async_resume, codec, &domain);
-		else
+			hda_call_codec_suspend(codec);
 			hda_call_codec_resume(codec);
+		}
+#endif
 	}
-
-	if (bus->num_codecs > 1)
-		async_synchronize_full_domain(&domain);
-
-	return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hda_resume);
-#endif /* CONFIG_PM */
-
-/*
- * generic arrays
- */
-
-/**
- * snd_array_new - get a new element from the given array
- * @array: the array object
- *
- * Get a new element from the given array.  If it exceeds the
- * pre-allocated array size, re-allocate the array.
- *
- * Returns NULL if allocation failed.
- */
-void *snd_array_new(struct snd_array *array)
-{
-	if (snd_BUG_ON(!array->elem_size))
-		return NULL;
-	if (array->used >= array->alloced) {
-		int num = array->alloced + array->alloc_align;
-		int size = (num + 1) * array->elem_size;
-		void *nlist;
-		if (snd_BUG_ON(num >= 4096))
-			return NULL;
-		nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
-		if (!nlist)
-			return NULL;
-		array->list = nlist;
-		array->alloced = num;
-	}
-	return snd_array_elem(array, array->used++);
-}
-EXPORT_SYMBOL_GPL(snd_array_new);
-
-/**
- * snd_array_free - free the given array elements
- * @array: the array object
- */
-void snd_array_free(struct snd_array *array)
-{
-	kfree(array->list);
-	array->used = 0;
-	array->alloced = 0;
-	array->list = NULL;
-}
-EXPORT_SYMBOL_GPL(snd_array_free);
+EXPORT_SYMBOL_GPL(snd_hda_bus_reset);
 
 /**
  * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 9c8820f..9075ac2 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -21,41 +21,14 @@
 #ifndef __SOUND_HDA_CODEC_H
 #define __SOUND_HDA_CODEC_H
 
+#include <linux/kref.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/hwdep.h>
+#include <sound/hdaudio.h>
 #include <sound/hda_verbs.h>
-
-/*
- * generic arrays
- */
-struct snd_array {
-	unsigned int used;
-	unsigned int alloced;
-	unsigned int elem_size;
-	unsigned int alloc_align;
-	void *list;
-};
-
-void *snd_array_new(struct snd_array *array);
-void snd_array_free(struct snd_array *array);
-static inline void snd_array_init(struct snd_array *array, unsigned int size,
-				  unsigned int align)
-{
-	array->elem_size = size;
-	array->alloc_align = align;
-}
-
-static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
-{
-	return array->list + idx * array->elem_size;
-}
-
-static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
-{
-	return (unsigned long)(ptr - array->list) / array->elem_size;
-}
+#include <sound/hda_regmap.h>
 
 /*
  * Structures
@@ -66,10 +39,6 @@
 struct hda_codec;
 struct hda_pcm;
 struct hda_pcm_stream;
-struct hda_bus_unsolicited;
-
-/* NID type */
-typedef u16 hda_nid_t;
 
 /* bus operators */
 struct hda_bus_ops {
@@ -84,10 +53,6 @@
 			  struct hda_pcm *pcm);
 	/* reset bus for retry verb */
 	void (*bus_reset)(struct hda_bus *bus);
-#ifdef CONFIG_PM
-	/* notify power-up/down from codec to controller */
-	void (*pm_notify)(struct hda_bus *bus, bool power_up);
-#endif
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 	/* prepare DSP transfer */
 	int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
@@ -101,15 +66,6 @@
 #endif
 };
 
-/* template to pass to the bus constructor */
-struct hda_bus_template {
-	void *private_data;
-	struct pci_dev *pci;
-	const char *modelname;
-	int *power_save;
-	struct hda_bus_ops ops;
-};
-
 /*
  * codec bus
  *
@@ -117,42 +73,28 @@
  * A hda_bus contains several codecs in the list codec_list.
  */
 struct hda_bus {
+	struct hdac_bus core;
+
 	struct snd_card *card;
 
-	/* copied from template */
 	void *private_data;
 	struct pci_dev *pci;
 	const char *modelname;
-	int *power_save;
 	struct hda_bus_ops ops;
 
-	/* codec linked list */
-	struct list_head codec_list;
-	unsigned int num_codecs;
-	/* link caddr -> codec */
-	struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
-
-	struct mutex cmd_mutex;
 	struct mutex prepare_mutex;
 
-	/* unsolicited event queue */
-	struct hda_bus_unsolicited *unsol;
-	char workq_name[16];
-	struct workqueue_struct *workq;	/* common workqueue for codecs */
-
 	/* assigned PCMs */
 	DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
 
 	/* misc op flags */
 	unsigned int needs_damn_long_delay :1;
 	unsigned int allow_bus_reset:1;	/* allow bus reset at fatal error */
-	unsigned int sync_write:1;	/* sync after verb write */
 	/* status for codec/controller */
 	unsigned int shutdown :1;	/* being unloaded */
 	unsigned int rirb_error:1;	/* error in codec communication */
 	unsigned int response_reset:1;	/* controller was reset */
 	unsigned int in_reset:1;	/* during reset operation */
-	unsigned int power_keep_link_on:1; /* don't power off HDA link */
 	unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
 
 	int primary_dig_out_type;	/* primary digital out PCM type */
@@ -175,15 +117,22 @@
 	int (*patch)(struct hda_codec *codec);
 };
 	
-struct hda_codec_preset_list {
+#define HDA_CODEC_ID_GENERIC_HDMI	0x00000101
+#define HDA_CODEC_ID_GENERIC		0x00000201
+
+struct hda_codec_driver {
+	struct hdac_driver core;
 	const struct hda_codec_preset *preset;
-	struct module *owner;
-	struct list_head list;
 };
 
-/* initial hook */
-int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset);
-int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset);
+int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
+			       struct module *owner);
+#define hda_codec_driver_register(drv) \
+	__hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE)
+void hda_codec_driver_unregister(struct hda_codec_driver *drv);
+#define module_hda_codec_driver(drv) \
+	module_driver(drv, hda_codec_driver_register, \
+		      hda_codec_driver_unregister)
 
 /* ops set by the preset patch */
 struct hda_codec_ops {
@@ -200,25 +149,7 @@
 	int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
 #endif
 	void (*reboot_notify)(struct hda_codec *codec);
-};
-
-/* record for amp information cache */
-struct hda_cache_head {
-	u32 key:31;		/* hash key */
-	u32 dirty:1;
-	u16 val;		/* assigned value */
-	u16 next;
-};
-
-struct hda_amp_info {
-	struct hda_cache_head head;
-	u32 amp_caps;		/* amp capabilities */
-	u16 vol[2];		/* current volume & mute */
-};
-
-struct hda_cache_rec {
-	u16 hash[64];			/* hash table for index */
-	struct snd_array buf;		/* record entries */
+	void (*stream_pm)(struct hda_codec *codec, hda_nid_t nid, bool on);
 };
 
 /* PCM callbacks */
@@ -267,41 +198,29 @@
 	int device;		/* device number to assign */
 	struct snd_pcm *pcm;	/* assigned PCM instance */
 	bool own_chmap;		/* codec driver provides own channel maps */
+	/* private: */
+	struct hda_codec *codec;
+	struct kref kref;
+	struct list_head list;
 };
 
 /* codec information */
 struct hda_codec {
-	struct device dev;
+	struct hdac_device core;
 	struct hda_bus *bus;
+	struct snd_card *card;
 	unsigned int addr;	/* codec addr*/
-	struct list_head list;	/* list point */
-
-	hda_nid_t afg;	/* AFG node id */
-	hda_nid_t mfg;	/* MFG node id */
-
-	/* ids */
-	u8 afg_function_id;
-	u8 mfg_function_id;
-	u8 afg_unsol;
-	u8 mfg_unsol;
-	u32 vendor_id;
-	u32 subsystem_id;
-	u32 revision_id;
+	u32 probe_id; /* overridden id for probing */
 
 	/* detected preset */
 	const struct hda_codec_preset *preset;
-	struct module *owner;
-	int (*parser)(struct hda_codec *codec);
-	const char *vendor_name;	/* codec vendor name */
-	const char *chip_name;		/* codec chip name */
 	const char *modelname;	/* model name for preset */
 
 	/* set by patch */
 	struct hda_codec_ops patch_ops;
 
 	/* PCM to create, set by patch_ops.build_pcms callback */
-	unsigned int num_pcms;
-	struct hda_pcm *pcm_info;
+	struct list_head pcm_list_head;
 
 	/* codec specific info */
 	void *spec;
@@ -311,21 +230,15 @@
 	unsigned int beep_mode;
 
 	/* widget capabilities cache */
-	unsigned int num_nodes;
-	hda_nid_t start_nid;
 	u32 *wcaps;
 
 	struct snd_array mixers;	/* list of assigned mixer elements */
 	struct snd_array nids;		/* list of mapped mixer elements */
 
-	struct hda_cache_rec amp_cache;	/* cache for amp access */
-	struct hda_cache_rec cmd_cache;	/* cache for other commands */
-
 	struct list_head conn_list;	/* linked-list of connection-list */
 
 	struct mutex spdif_mutex;
 	struct mutex control_mutex;
-	struct mutex hash_mutex;
 	struct snd_array spdif_out;
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
 	const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
@@ -345,6 +258,8 @@
 #endif
 
 	/* misc flags */
+	unsigned int in_freeing:1; /* being released */
+	unsigned int registered:1; /* codec was registered */
 	unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
 					     * status change
 					     * (e.g. Realtek codecs)
@@ -362,22 +277,14 @@
 	unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */
 	unsigned int inv_jack_detect:1;	/* broken h/w: inverted detection bit */
 	unsigned int pcm_format_first:1; /* PCM format must be set first */
-	unsigned int epss:1;		/* supporting EPSS? */
 	unsigned int cached_write:1;	/* write only to caches */
 	unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
 	unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
+	unsigned int power_save_node:1; /* advanced PM for each widget */
 #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_up_notified:1;	/* PM notified to controller */
-	unsigned int in_pm:1;		/* suspend/resume being performed */
-	int power_transition;	/* power-state in transition */
-	int power_count;	/* current (global) power refcount */
-	struct delayed_work power_work; /* delayed task for powerdown */
 	unsigned long power_on_acct;
 	unsigned long power_off_acct;
 	unsigned long power_jiffies;
-	spinlock_t power_lock;
 #endif
 
 	/* filter the requested power state per nid */
@@ -409,10 +316,11 @@
 	struct snd_array verbs;
 };
 
-/* direction */
-enum {
-	HDA_INPUT, HDA_OUTPUT
-};
+#define dev_to_hda_codec(_dev)	container_of(_dev, struct hda_codec, core.dev)
+#define hda_codec_dev(_dev)	(&(_dev)->core.dev)
+
+#define list_for_each_codec(c, bus) \
+	list_for_each_entry(c, &(bus)->core.codec_list, core.list)
 
 /* snd_hda_codec_read/write optional flags */
 #define HDA_RW_NO_RESPONSE_FALLBACK	(1 << 0)
@@ -420,10 +328,9 @@
 /*
  * constructors
  */
-int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
-		    struct hda_bus **busp);
-int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-		      struct hda_codec **codecp);
+int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp);
+int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
+		      unsigned int codec_addr, struct hda_codec **codecp);
 int snd_hda_codec_configure(struct hda_codec *codec);
 int snd_hda_codec_update_widgets(struct hda_codec *codec);
 
@@ -436,9 +343,9 @@
 int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
 			unsigned int verb, unsigned int parm);
 #define snd_hda_param_read(codec, nid, param) \
-	snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param)
-int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
-			  hda_nid_t *start_id);
+	snd_hdac_read_parm(&(codec)->core, nid, param)
+#define snd_hda_get_sub_nodes(codec, nid, start_nid) \
+	snd_hdac_get_sub_nodes(&(codec)->core, nid, start_nid)
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 			    hda_nid_t *conn_list, int max_conns);
 static inline int
@@ -446,9 +353,12 @@
 {
 	return snd_hda_get_connections(codec, nid, NULL, 0);
 }
-int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
-			    hda_nid_t *conn_list, int max_conns);
+
+#define snd_hda_get_raw_connections(codec, nid, list, max_conns) \
+	snd_hdac_get_connections(&(codec)->core, nid, list, max_conns)
+#define snd_hda_get_num_raw_conns(codec, nid) \
+	snd_hdac_get_connections(&(codec)->core, nid, NULL, 0);
+
 int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 			  const hda_nid_t **listp);
 int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
@@ -470,18 +380,22 @@
 			    const struct hda_verb *seq);
 
 /* unsolicited event */
-int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
+static inline void
+snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
+{
+	snd_hdac_bus_queue_event(&bus->core, res, res_ex);
+}
 
 /* cached write */
-int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
-			      int flags, unsigned int verb, unsigned int parm);
-void snd_hda_sequence_write_cache(struct hda_codec *codec,
-				  const struct hda_verb *seq);
-int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
-			      int flags, unsigned int verb, unsigned int parm);
-void snd_hda_codec_resume_cache(struct hda_codec *codec);
-/* both for cmd & amp caches */
-void snd_hda_codec_flush_cache(struct hda_codec *codec);
+static inline int
+snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
+			  int flags, unsigned int verb, unsigned int parm)
+{
+	return snd_hdac_regmap_write(&codec->core, nid, verb, parm);
+}
+
+#define snd_hda_codec_update_cache(codec, nid, flags, verb, parm) \
+	snd_hda_codec_write_cache(codec, nid, flags, verb, parm)
 
 /* the struct for codec->pin_configs */
 struct hda_pincfg {
@@ -512,15 +426,24 @@
 /*
  * Mixer
  */
-int snd_hda_build_controls(struct hda_bus *bus);
 int snd_hda_codec_build_controls(struct hda_codec *codec);
 
 /*
  * PCM
  */
-int snd_hda_build_pcms(struct hda_bus *bus);
+int snd_hda_codec_parse_pcms(struct hda_codec *codec);
 int snd_hda_codec_build_pcms(struct hda_codec *codec);
 
+__printf(2, 3)
+struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
+				      const char *fmt, ...);
+
+static inline void snd_hda_codec_pcm_get(struct hda_pcm *pcm)
+{
+	kref_get(&pcm->kref);
+}
+void snd_hda_codec_pcm_put(struct hda_pcm *pcm);
+
 int snd_hda_codec_prepare(struct hda_codec *codec,
 			  struct hda_pcm_stream *hinfo,
 			  unsigned int stream,
@@ -552,20 +475,17 @@
  * Misc
  */
 void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
-void snd_hda_bus_reboot_notify(struct hda_bus *bus);
 void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
 				    unsigned int power_state);
 
 int snd_hda_lock_devices(struct hda_bus *bus);
 void snd_hda_unlock_devices(struct hda_bus *bus);
+void snd_hda_bus_reset(struct hda_bus *bus);
 
 /*
  * power management
  */
-#ifdef CONFIG_PM
-int snd_hda_suspend(struct hda_bus *bus);
-int snd_hda_resume(struct hda_bus *bus);
-#endif
+extern const struct dev_pm_ops hda_codec_driver_pm;
 
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
@@ -587,65 +507,17 @@
 /*
  * power saving
  */
+#define snd_hda_power_up(codec)		snd_hdac_power_up(&(codec)->core)
+#define snd_hda_power_up_pm(codec)	snd_hdac_power_up_pm(&(codec)->core)
+#define snd_hda_power_down(codec)	snd_hdac_power_down(&(codec)->core)
+#define snd_hda_power_down_pm(codec)	snd_hdac_power_down_pm(&(codec)->core)
 #ifdef CONFIG_PM
-void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
+void snd_hda_set_power_save(struct hda_bus *bus, int delay);
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
-static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
-				      bool d3wait) {}
+static inline void snd_hda_set_power_save(struct hda_bus *bus, int delay) {}
 #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
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 17c2637..26ce990 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -27,10 +27,8 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
-#include <linux/reboot.h>
 #include <sound/core.h>
 #include <sound/initval.h>
-#include "hda_priv.h"
 #include "hda_controller.h"
 
 #define CREATE_TRACE_POINTS
@@ -259,11 +257,18 @@
 		tc->cycle_last = last;
 }
 
+static inline struct hda_pcm_stream *
+to_hda_pcm_stream(struct snd_pcm_substream *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	return &apcm->info->stream[substream->stream];
+}
+
 static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
 				u64 nsec)
 {
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	u64 codec_frames, codec_nsecs;
 
 	if (!hinfo->ops.get_delay)
@@ -399,7 +404,7 @@
 static int azx_pcm_close(struct snd_pcm_substream *substream)
 {
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	struct azx *chip = apcm->chip;
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	unsigned long flags;
@@ -410,9 +415,11 @@
 	azx_dev->running = 0;
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	azx_release_device(azx_dev);
-	hinfo->ops.close(hinfo, apcm->codec, substream);
+	if (hinfo->ops.close)
+		hinfo->ops.close(hinfo, apcm->codec, substream);
 	snd_hda_power_down(apcm->codec);
 	mutex_unlock(&chip->open_mutex);
+	snd_hda_codec_pcm_put(apcm->info);
 	return 0;
 }
 
@@ -441,7 +448,7 @@
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	struct azx *chip = apcm->chip;
-	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	int err;
 
 	/* reset BDL address */
@@ -468,7 +475,7 @@
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	struct azx *chip = apcm->chip;
 	struct azx_dev *azx_dev = get_azx_dev(substream);
-	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	unsigned int bufsize, period_bytes, format_val, stream_tag;
 	int err;
@@ -708,7 +715,7 @@
 
 	if (substream->runtime) {
 		struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-		struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
+		struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 
 		if (chip->get_delay[stream])
 			delay += chip->get_delay[stream](chip, azx_dev, pos);
@@ -732,17 +739,32 @@
 			       azx_get_position(chip, azx_dev));
 }
 
-static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
-				struct timespec *ts)
+static int azx_get_time_info(struct snd_pcm_substream *substream,
+			struct timespec *system_ts, struct timespec *audio_ts,
+			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
+			struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
 {
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	u64 nsec;
 
-	nsec = timecounter_read(&azx_dev->azx_tc);
-	nsec = div_u64(nsec, 3); /* can be optimized */
-	nsec = azx_adjust_codec_delay(substream, nsec);
+	if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
+		(audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) {
 
-	*ts = ns_to_timespec(nsec);
+		snd_pcm_gettime(substream->runtime, system_ts);
+
+		nsec = timecounter_read(&azx_dev->azx_tc);
+		nsec = div_u64(nsec, 3); /* can be optimized */
+		if (audio_tstamp_config->report_delay)
+			nsec = azx_adjust_codec_delay(substream, nsec);
+
+		*audio_ts = ns_to_timespec(nsec);
+
+		audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
+		audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
+		audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
+
+	} else
+		audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
 
 	return 0;
 }
@@ -756,7 +778,8 @@
 				 /* SNDRV_PCM_INFO_RESUME |*/
 				 SNDRV_PCM_INFO_PAUSE |
 				 SNDRV_PCM_INFO_SYNC_START |
-				 SNDRV_PCM_INFO_HAS_WALL_CLOCK |
+				 SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
+				 SNDRV_PCM_INFO_HAS_LINK_ATIME |
 				 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =		SNDRV_PCM_RATE_48000,
@@ -775,7 +798,7 @@
 static int azx_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	struct azx *chip = apcm->chip;
 	struct azx_dev *azx_dev;
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -783,11 +806,12 @@
 	int err;
 	int buff_step;
 
+	snd_hda_codec_pcm_get(apcm->info);
 	mutex_lock(&chip->open_mutex);
 	azx_dev = azx_assign_device(chip, substream);
 	if (azx_dev == NULL) {
-		mutex_unlock(&chip->open_mutex);
-		return -EBUSY;
+		err = -EBUSY;
+		goto unlock;
 	}
 	runtime->hw = azx_pcm_hw;
 	runtime->hw.channels_min = hinfo->channels_min;
@@ -821,13 +845,14 @@
 				   buff_step);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 				   buff_step);
-	snd_hda_power_up_d3wait(apcm->codec);
-	err = hinfo->ops.open(hinfo, apcm->codec, substream);
+	snd_hda_power_up(apcm->codec);
+	if (hinfo->ops.open)
+		err = hinfo->ops.open(hinfo, apcm->codec, substream);
+	else
+		err = -ENODEV;
 	if (err < 0) {
 		azx_release_device(azx_dev);
-		snd_hda_power_down(apcm->codec);
-		mutex_unlock(&chip->open_mutex);
-		return err;
+		goto powerdown;
 	}
 	snd_pcm_limit_hw_rates(runtime);
 	/* sanity check */
@@ -836,16 +861,18 @@
 	    snd_BUG_ON(!runtime->hw.formats) ||
 	    snd_BUG_ON(!runtime->hw.rates)) {
 		azx_release_device(azx_dev);
-		hinfo->ops.close(hinfo, apcm->codec, substream);
-		snd_hda_power_down(apcm->codec);
-		mutex_unlock(&chip->open_mutex);
-		return -EINVAL;
+		if (hinfo->ops.close)
+			hinfo->ops.close(hinfo, apcm->codec, substream);
+		err = -EINVAL;
+		goto powerdown;
 	}
 
-	/* disable WALLCLOCK timestamps for capture streams
+	/* disable LINK_ATIME timestamps for capture streams
 	   until we figure out how to handle digital inputs */
-	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK;
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */
+		runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME;
+	}
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	azx_dev->substream = substream;
@@ -856,6 +883,13 @@
 	snd_pcm_set_sync(substream);
 	mutex_unlock(&chip->open_mutex);
 	return 0;
+
+ powerdown:
+	snd_hda_power_down(apcm->codec);
+ unlock:
+	mutex_unlock(&chip->open_mutex);
+	snd_hda_codec_pcm_put(apcm->info);
+	return err;
 }
 
 static int azx_pcm_mmap(struct snd_pcm_substream *substream,
@@ -877,7 +911,7 @@
 	.prepare = azx_pcm_prepare,
 	.trigger = azx_pcm_trigger,
 	.pointer = azx_pcm_pointer,
-	.wall_clock =  azx_get_wallclock_tstamp,
+	.get_time_info =  azx_get_time_info,
 	.mmap = azx_pcm_mmap,
 	.page = snd_pcm_sgbuf_ops_page,
 };
@@ -887,6 +921,7 @@
 	struct azx_pcm *apcm = pcm->private_data;
 	if (apcm) {
 		list_del(&apcm->list);
+		apcm->info->pcm = NULL;
 		kfree(apcm);
 	}
 }
@@ -923,6 +958,7 @@
 	apcm->chip = chip;
 	apcm->pcm = pcm;
 	apcm->codec = codec;
+	apcm->info = cpcm;
 	pcm->private_data = apcm;
 	pcm->private_free = azx_pcm_free;
 	if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
@@ -930,7 +966,6 @@
 	list_add_tail(&apcm->list, &chip->pcm_list);
 	cpcm->pcm = pcm;
 	for (s = 0; s < 2; s++) {
-		apcm->hinfo[s] = &cpcm->stream[s];
 		if (cpcm->stream[s].substreams)
 			snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
 	}
@@ -941,9 +976,6 @@
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      chip->card->dev,
 					      size, MAX_PREALLOC_SIZE);
-	/* link to codec */
-	for (s = 0; s < 2; s++)
-		pcm->streams[s].dev.parent = &codec->dev;
 	return 0;
 }
 
@@ -952,14 +984,9 @@
  */
 static int azx_alloc_cmd_io(struct azx *chip)
 {
-	int err;
-
 	/* single page (at least 4096 bytes) must suffice for both ringbuffes */
-	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
-					 PAGE_SIZE, &chip->rb);
-	if (err < 0)
-		dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
-	return err;
+	return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+					  PAGE_SIZE, &chip->rb);
 }
 
 static void azx_init_cmd_io(struct azx *chip)
@@ -1445,7 +1472,6 @@
 int azx_alloc_stream_pages(struct azx *chip)
 {
 	int i, err;
-	struct snd_card *card = chip->card;
 
 	for (i = 0; i < chip->num_streams; i++) {
 		dsp_lock_init(&chip->azx_dev[i]);
@@ -1453,18 +1479,14 @@
 		err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
 						 BDL_SIZE,
 						 &chip->azx_dev[i].bdl);
-		if (err < 0) {
-			dev_err(card->dev, "cannot allocate BDL\n");
+		if (err < 0)
 			return -ENOMEM;
-		}
 	}
 	/* allocate memory for the position buffer */
 	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
 					 chip->num_streams * 8, &chip->posbuf);
-	if (err < 0) {
-		dev_err(card->dev, "cannot allocate posbuf\n");
+	if (err < 0)
 		return -ENOMEM;
-	}
 
 	/* allocate CORB/RIRB */
 	err = azx_alloc_cmd_io(chip);
@@ -1676,7 +1698,7 @@
 	int i;
 
 #ifdef CONFIG_PM
-	if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+	if (azx_has_pm_runtime(chip))
 		if (!pm_runtime_active(chip->card->dev))
 			return IRQ_NONE;
 #endif
@@ -1742,12 +1764,12 @@
 		(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
 	unsigned int res;
 
-	mutex_lock(&chip->bus->cmd_mutex);
+	mutex_lock(&chip->bus->core.cmd_mutex);
 	chip->probing = 1;
 	azx_send_cmd(chip->bus, cmd);
 	res = azx_get_response(chip->bus, addr);
 	chip->probing = 0;
-	mutex_unlock(&chip->bus->cmd_mutex);
+	mutex_unlock(&chip->bus->core.cmd_mutex);
 	if (res == -1)
 		return -EIO;
 	dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
@@ -1761,34 +1783,11 @@
 	bus->in_reset = 1;
 	azx_stop_chip(chip);
 	azx_init_chip(chip, true);
-#ifdef CONFIG_PM
-	if (chip->initialized) {
-		struct azx_pcm *p;
-		list_for_each_entry(p, &chip->pcm_list, list)
-			snd_pcm_suspend_all(p->pcm);
-		snd_hda_suspend(chip->bus);
-		snd_hda_resume(chip->bus);
-	}
-#endif
+	if (chip->initialized)
+		snd_hda_bus_reset(chip->bus);
 	bus->in_reset = 0;
 }
 
-#ifdef CONFIG_PM
-/* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus, bool power_up)
-{
-	struct azx *chip = bus->private_data;
-
-	if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
-		return;
-
-	if (power_up)
-		pm_runtime_get_sync(chip->card->dev);
-	else
-		pm_runtime_put_sync(chip->card->dev);
-}
-#endif
-
 static int get_jackpoll_interval(struct azx *chip)
 {
 	int i;
@@ -1810,41 +1809,59 @@
 	return j;
 }
 
-/* Codec initialization */
-int azx_codec_create(struct azx *chip, const char *model,
-		     unsigned int max_slots,
-		     int *power_save_to)
-{
-	struct hda_bus_template bus_temp;
-	int c, codecs, err;
-
-	memset(&bus_temp, 0, sizeof(bus_temp));
-	bus_temp.private_data = chip;
-	bus_temp.modelname = model;
-	bus_temp.pci = chip->pci;
-	bus_temp.ops.command = azx_send_cmd;
-	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_PM
-	bus_temp.power_save = power_save_to;
-	bus_temp.ops.pm_notify = azx_power_notify;
-#endif
+static struct hda_bus_ops bus_ops = {
+	.command = azx_send_cmd,
+	.get_response = azx_get_response,
+	.attach_pcm = azx_attach_pcm_stream,
+	.bus_reset = azx_bus_reset,
 #ifdef CONFIG_SND_HDA_DSP_LOADER
-	bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
-	bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
-	bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
+	.load_dsp_prepare = azx_load_dsp_prepare,
+	.load_dsp_trigger = azx_load_dsp_trigger,
+	.load_dsp_cleanup = azx_load_dsp_cleanup,
 #endif
+};
 
-	err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
+/* HD-audio bus initialization */
+int azx_bus_create(struct azx *chip, const char *model)
+{
+	struct hda_bus *bus;
+	int err;
+
+	err = snd_hda_bus_new(chip->card, &bus);
 	if (err < 0)
 		return err;
 
+	chip->bus = bus;
+	bus->private_data = chip;
+	bus->pci = chip->pci;
+	bus->modelname = model;
+	bus->ops = bus_ops;
+
 	if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
 		dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
-		chip->bus->needs_damn_long_delay = 1;
+		bus->needs_damn_long_delay = 1;
 	}
 
+	/* AMD chipsets often cause the communication stalls upon certain
+	 * sequence like the pin-detection.  It seems that forcing the synced
+	 * access works around the stall.  Grrr...
+	 */
+	if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+		dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
+		bus->core.sync_write = 1;
+		bus->allow_bus_reset = 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(azx_bus_create);
+
+/* Probe codecs */
+int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
+{
+	struct hda_bus *bus = chip->bus;
+	int c, codecs, err;
+
 	codecs = 0;
 	if (!max_slots)
 		max_slots = AZX_DEFAULT_CODECS;
@@ -1872,21 +1889,11 @@
 		}
 	}
 
-	/* AMD chipsets often cause the communication stalls upon certain
-	 * sequence like the pin-detection.  It seems that forcing the synced
-	 * access works around the stall.  Grrr...
-	 */
-	if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
-		dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
-		chip->bus->sync_write = 1;
-		chip->bus->allow_bus_reset = 1;
-	}
-
 	/* Then create codec instances */
 	for (c = 0; c < max_slots; c++) {
 		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
 			struct hda_codec *codec;
-			err = snd_hda_codec_new(chip->bus, c, &codec);
+			err = snd_hda_codec_new(bus, bus->card, c, &codec);
 			if (err < 0)
 				continue;
 			codec->jackpoll_interval = get_jackpoll_interval(chip);
@@ -1900,26 +1907,19 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL_GPL(azx_codec_create);
+EXPORT_SYMBOL_GPL(azx_probe_codecs);
 
 /* configure each codec instance */
 int azx_codec_configure(struct azx *chip)
 {
 	struct hda_codec *codec;
-	list_for_each_entry(codec, &chip->bus->codec_list, list) {
+	list_for_each_codec(codec, chip->bus) {
 		snd_hda_codec_configure(codec);
 	}
 	return 0;
 }
 EXPORT_SYMBOL_GPL(azx_codec_configure);
 
-/* mixer creation - all stuff is implemented in hda module */
-int azx_mixer_create(struct azx *chip)
-{
-	return snd_hda_build_controls(chip->bus);
-}
-EXPORT_SYMBOL_GPL(azx_mixer_create);
-
 
 static bool is_input_stream(struct azx *chip, unsigned char index)
 {
@@ -1966,30 +1966,5 @@
 }
 EXPORT_SYMBOL_GPL(azx_init_stream);
 
-/*
- * reboot notifier for hang-up problem at power-down
- */
-static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
-{
-	struct azx *chip = container_of(nb, struct azx, reboot_notifier);
-	snd_hda_bus_reboot_notify(chip->bus);
-	azx_stop_chip(chip);
-	return NOTIFY_OK;
-}
-
-void azx_notifier_register(struct azx *chip)
-{
-	chip->reboot_notifier.notifier_call = azx_halt;
-	register_reboot_notifier(&chip->reboot_notifier);
-}
-EXPORT_SYMBOL_GPL(azx_notifier_register);
-
-void azx_notifier_unregister(struct azx *chip)
-{
-	if (chip->reboot_notifier.notifier_call)
-		unregister_reboot_notifier(&chip->reboot_notifier);
-}
-EXPORT_SYMBOL_GPL(azx_notifier_unregister);
-
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Common HDA driver functions");
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index c90d10f..be1b7de 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -15,10 +15,396 @@
 #ifndef __SOUND_HDA_CONTROLLER_H
 #define __SOUND_HDA_CONTROLLER_H
 
+#include <linux/timecounter.h>
+#include <linux/interrupt.h>
 #include <sound/core.h>
+#include <sound/pcm.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
-#include "hda_priv.h"
+
+/*
+ * registers
+ */
+#define AZX_REG_GCAP			0x00
+#define   AZX_GCAP_64OK		(1 << 0)   /* 64bit address support */
+#define   AZX_GCAP_NSDO		(3 << 1)   /* # of serial data out signals */
+#define   AZX_GCAP_BSS		(31 << 3)  /* # of bidirectional streams */
+#define   AZX_GCAP_ISS		(15 << 8)  /* # of input streams */
+#define   AZX_GCAP_OSS		(15 << 12) /* # of output streams */
+#define AZX_REG_VMIN			0x02
+#define AZX_REG_VMAJ			0x03
+#define AZX_REG_OUTPAY			0x04
+#define AZX_REG_INPAY			0x06
+#define AZX_REG_GCTL			0x08
+#define   AZX_GCTL_RESET	(1 << 0)   /* controller reset */
+#define   AZX_GCTL_FCNTRL	(1 << 1)   /* flush control */
+#define   AZX_GCTL_UNSOL	(1 << 8)   /* accept unsol. response enable */
+#define AZX_REG_WAKEEN			0x0c
+#define AZX_REG_STATESTS		0x0e
+#define AZX_REG_GSTS			0x10
+#define   AZX_GSTS_FSTS		(1 << 1)   /* flush status */
+#define AZX_REG_INTCTL			0x20
+#define AZX_REG_INTSTS			0x24
+#define AZX_REG_WALLCLK			0x30	/* 24Mhz source */
+#define AZX_REG_OLD_SSYNC		0x34	/* SSYNC for old ICH */
+#define AZX_REG_SSYNC			0x38
+#define AZX_REG_CORBLBASE		0x40
+#define AZX_REG_CORBUBASE		0x44
+#define AZX_REG_CORBWP			0x48
+#define AZX_REG_CORBRP			0x4a
+#define   AZX_CORBRP_RST	(1 << 15)  /* read pointer reset */
+#define AZX_REG_CORBCTL			0x4c
+#define   AZX_CORBCTL_RUN	(1 << 1)   /* enable DMA */
+#define   AZX_CORBCTL_CMEIE	(1 << 0)   /* enable memory error irq */
+#define AZX_REG_CORBSTS			0x4d
+#define   AZX_CORBSTS_CMEI	(1 << 0)   /* memory error indication */
+#define AZX_REG_CORBSIZE		0x4e
+
+#define AZX_REG_RIRBLBASE		0x50
+#define AZX_REG_RIRBUBASE		0x54
+#define AZX_REG_RIRBWP			0x58
+#define   AZX_RIRBWP_RST	(1 << 15)  /* write pointer reset */
+#define AZX_REG_RINTCNT			0x5a
+#define AZX_REG_RIRBCTL			0x5c
+#define   AZX_RBCTL_IRQ_EN	(1 << 0)   /* enable IRQ */
+#define   AZX_RBCTL_DMA_EN	(1 << 1)   /* enable DMA */
+#define   AZX_RBCTL_OVERRUN_EN	(1 << 2)   /* enable overrun irq */
+#define AZX_REG_RIRBSTS			0x5d
+#define   AZX_RBSTS_IRQ		(1 << 0)   /* response irq */
+#define   AZX_RBSTS_OVERRUN	(1 << 2)   /* overrun irq */
+#define AZX_REG_RIRBSIZE		0x5e
+
+#define AZX_REG_IC			0x60
+#define AZX_REG_IR			0x64
+#define AZX_REG_IRS			0x68
+#define   AZX_IRS_VALID		(1<<1)
+#define   AZX_IRS_BUSY		(1<<0)
+
+#define AZX_REG_DPLBASE			0x70
+#define AZX_REG_DPUBASE			0x74
+#define   AZX_DPLBASE_ENABLE	0x1	/* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define AZX_REG_SD_CTL			0x00
+#define AZX_REG_SD_STS			0x03
+#define AZX_REG_SD_LPIB			0x04
+#define AZX_REG_SD_CBL			0x08
+#define AZX_REG_SD_LVI			0x0c
+#define AZX_REG_SD_FIFOW		0x0e
+#define AZX_REG_SD_FIFOSIZE		0x10
+#define AZX_REG_SD_FORMAT		0x12
+#define AZX_REG_SD_BDLPL		0x18
+#define AZX_REG_SD_BDLPU		0x1c
+
+/* PCI space */
+#define AZX_PCIREG_TCSEL		0x44
+
+/*
+ * other constants
+ */
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE		4096
+#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
+#define AZX_MAX_FRAG		32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE	0x01
+#define RIRB_INT_OVERRUN	0x04
+#define RIRB_INT_MASK		0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS		8
+#define AZX_DEFAULT_CODECS	4
+#define STATESTS_INT_MASK	((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
+#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
+#define SD_CTL_STRIPE		(3 << 16)	/* stripe control */
+#define SD_CTL_TRAFFIC_PRIO	(1 << 18)	/* traffic priority */
+#define SD_CTL_DIR		(1 << 19)	/* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT	20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
+#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
+#define SD_INT_COMPLETE		0x04	/* completion interrupt */
+#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+				 SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define AZX_INT_ALL_STREAM	0xff	   /* all stream interrupts */
+#define AZX_INT_CTRL_EN	0x40000000 /* controller interrupt enable bit */
+#define AZX_INT_GLOBAL_EN	0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define AZX_MAX_CORB_ENTRIES	256
+#define AZX_MAX_RIRB_ENTRIES	256
+
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL	(1 << 8)	/* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI	(1 << 9)	/* No MSI support */
+#define AZX_DCAPS_SNOOP_MASK	(3 << 10)	/* snoop type mask */
+#define AZX_DCAPS_SNOOP_OFF	(1 << 12)	/* snoop default off */
+#define AZX_DCAPS_RIRB_DELAY	(1 << 13)	/* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)	/* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)	/* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB	(1 << 16)	/* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA	(1 << 17)	/* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT	(1 << 18)	/* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
+#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21)	/* no buffer size alignment */
+/* 22 unused */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
+#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24)	/* Assign devices in reverse order */
+#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)	/* Take LPIB as delay */
+#define AZX_DCAPS_PM_RUNTIME	(1 << 26)	/* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL (1 << 27)	/* HSW i915 powerwell support */
+#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)	/* CORBRP clears itself after reset */
+#define AZX_DCAPS_NO_MSI64      (1 << 29)	/* Stick to 32-bit MSIs */
+#define AZX_DCAPS_SEPARATE_STREAM_TAG	(1 << 30) /* capture and playback use separate stream tag */
+
+enum {
+	AZX_SNOOP_TYPE_NONE,
+	AZX_SNOOP_TYPE_SCH,
+	AZX_SNOOP_TYPE_ATI,
+	AZX_SNOOP_TYPE_NVIDIA,
+};
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
+
+struct azx_dev {
+	struct snd_dma_buffer bdl; /* BDL buffer */
+	u32 *posbuf;		/* position buffer pointer */
+
+	unsigned int bufsize;	/* size of the play buffer in bytes */
+	unsigned int period_bytes; /* size of the period in bytes */
+	unsigned int frags;	/* number for period in the play buffer */
+	unsigned int fifo_size;	/* FIFO size */
+	unsigned long start_wallclk;	/* start + minimum wallclk */
+	unsigned long period_wallclk;	/* wallclk for period */
+
+	void __iomem *sd_addr;	/* stream descriptor pointer */
+
+	u32 sd_int_sta_mask;	/* stream int status mask */
+
+	/* pcm support */
+	struct snd_pcm_substream *substream;	/* assigned substream,
+						 * set in PCM open
+						 */
+	unsigned int format_val;	/* format value to be set in the
+					 * controller and the codec
+					 */
+	unsigned char stream_tag;	/* assigned stream */
+	unsigned char index;		/* stream index */
+	int assigned_key;		/* last device# key assigned to */
+
+	unsigned int opened:1;
+	unsigned int running:1;
+	unsigned int irq_pending:1;
+	unsigned int prepared:1;
+	unsigned int locked:1;
+	/*
+	 * For VIA:
+	 *  A flag to ensure DMA position is 0
+	 *  when link position is not greater than FIFO size
+	 */
+	unsigned int insufficient:1;
+	unsigned int wc_marked:1;
+	unsigned int no_period_wakeup:1;
+
+	struct timecounter  azx_tc;
+	struct cyclecounter azx_cc;
+
+	int delay_negative_threshold;
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+	/* Allows dsp load to have sole access to the playback stream. */
+	struct mutex dsp_mutex;
+#endif
+};
+
+/* CORB/RIRB */
+struct azx_rb {
+	u32 *buf;		/* CORB/RIRB buffer
+				 * Each CORB entry is 4byte, RIRB is 8byte
+				 */
+	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
+	/* for RIRB */
+	unsigned short rp, wp;	/* read/write pointers */
+	int cmds[AZX_MAX_CODECS];	/* number of pending requests */
+	u32 res[AZX_MAX_CODECS];	/* last read value */
+};
+
+struct azx;
+
+/* Functions to read/write to hda registers. */
+struct hda_controller_ops {
+	/* Register Access */
+	void (*reg_writel)(u32 value, u32 __iomem *addr);
+	u32 (*reg_readl)(u32 __iomem *addr);
+	void (*reg_writew)(u16 value, u16 __iomem *addr);
+	u16 (*reg_readw)(u16 __iomem *addr);
+	void (*reg_writeb)(u8 value, u8 __iomem *addr);
+	u8 (*reg_readb)(u8 __iomem *addr);
+	/* Disable msi if supported, PCI only */
+	int (*disable_msi_reset_irq)(struct azx *);
+	/* Allocation ops */
+	int (*dma_alloc_pages)(struct azx *chip,
+			       int type,
+			       size_t size,
+			       struct snd_dma_buffer *buf);
+	void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf);
+	int (*substream_alloc_pages)(struct azx *chip,
+				     struct snd_pcm_substream *substream,
+				     size_t size);
+	int (*substream_free_pages)(struct azx *chip,
+				    struct snd_pcm_substream *substream);
+	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
+				 struct vm_area_struct *area);
+	/* Check if current position is acceptable */
+	int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
+};
+
+struct azx_pcm {
+	struct azx *chip;
+	struct snd_pcm *pcm;
+	struct hda_codec *codec;
+	struct hda_pcm *info;
+	struct list_head list;
+};
+
+typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *);
+typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos);
+
+struct azx {
+	struct snd_card *card;
+	struct pci_dev *pci;
+	int dev_index;
+
+	/* chip type specific */
+	int driver_type;
+	unsigned int driver_caps;
+	int playback_streams;
+	int playback_index_offset;
+	int capture_streams;
+	int capture_index_offset;
+	int num_streams;
+	const int *jackpoll_ms; /* per-card jack poll interval */
+
+	/* Register interaction. */
+	const struct hda_controller_ops *ops;
+
+	/* position adjustment callbacks */
+	azx_get_pos_callback_t get_position[2];
+	azx_get_delay_callback_t get_delay[2];
+
+	/* pci resources */
+	unsigned long addr;
+	void __iomem *remap_addr;
+	int irq;
+
+	/* locks */
+	spinlock_t reg_lock;
+	struct mutex open_mutex; /* Prevents concurrent open/close operations */
+
+	/* streams (x num_streams) */
+	struct azx_dev *azx_dev;
+
+	/* PCM */
+	struct list_head pcm_list; /* azx_pcm list */
+
+	/* HD codec */
+	unsigned short codec_mask;
+	int  codec_probe_mask; /* copied from probe_mask option */
+	struct hda_bus *bus;
+	unsigned int beep_mode;
+
+	/* CORB/RIRB */
+	struct azx_rb corb;
+	struct azx_rb rirb;
+
+	/* CORB/RIRB and position buffers */
+	struct snd_dma_buffer rb;
+	struct snd_dma_buffer posbuf;
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+	const struct firmware *fw;
+#endif
+
+	/* flags */
+	const int *bdl_pos_adj;
+	int poll_count;
+	unsigned int running:1;
+	unsigned int initialized:1;
+	unsigned int single_cmd:1;
+	unsigned int polling_mode:1;
+	unsigned int msi:1;
+	unsigned int probing:1; /* codec probing phase */
+	unsigned int snoop:1;
+	unsigned int align_buffer_size:1;
+	unsigned int region_requested:1;
+	unsigned int disabled:1; /* disabled by VGA-switcher */
+
+	/* for debugging */
+	unsigned int last_cmd[AZX_MAX_CODECS];
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+	struct azx_dev saved_azx_dev;
+#endif
+};
+
+#ifdef CONFIG_X86
+#define azx_snoop(chip)		((chip)->snoop)
+#else
+#define azx_snoop(chip)		true
+#endif
+
+/*
+ * macros for easy use
+ */
+
+#define azx_writel(chip, reg, value) \
+	((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readl(chip, reg) \
+	((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg))
+#define azx_writew(chip, reg, value) \
+	((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readw(chip, reg) \
+	((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg))
+#define azx_writeb(chip, reg, value) \
+	((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readb(chip, reg) \
+	((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg))
+
+#define azx_sd_writel(chip, dev, reg, value) \
+	((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readl(chip, dev, reg) \
+	((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_writew(chip, dev, reg, value) \
+	((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readw(chip, dev, reg) \
+	((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_writeb(chip, dev, reg, value) \
+	((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readb(chip, dev, reg) \
+	((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg))
+
+#define azx_has_pm_runtime(chip) \
+	(!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME))
 
 /* PCM setup */
 static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
@@ -43,14 +429,9 @@
 irqreturn_t azx_interrupt(int irq, void *dev_id);
 
 /* Codec interface */
-int azx_codec_create(struct azx *chip, const char *model,
-		     unsigned int max_slots,
-		     int *power_save_to);
+int azx_bus_create(struct azx *chip, const char *model);
+int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
 int azx_codec_configure(struct azx *chip);
-int azx_mixer_create(struct azx *chip);
 int azx_init_stream(struct azx *chip);
 
-void azx_notifier_register(struct azx *chip);
-void azx_notifier_unregister(struct azx *chip);
-
 #endif /* __SOUND_HDA_CONTROLLER_H */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 8ec5289..3d2597b 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -140,6 +140,9 @@
 	val = snd_hda_get_bool_hint(codec, "single_adc_amp");
 	if (val >= 0)
 		codec->single_adc_amp = !!val;
+	val = snd_hda_get_bool_hint(codec, "power_save_node");
+	if (val >= 0)
+		codec->power_save_node = !!val;
 
 	val = snd_hda_get_bool_hint(codec, "auto_mute");
 	if (val >= 0)
@@ -648,12 +651,24 @@
 			  unsigned int dir, unsigned int idx)
 {
 	struct hda_gen_spec *spec = codec->spec;
+	int type = get_wcaps_type(get_wcaps(codec, nid));
 	int i, n;
 
+	if (nid == codec->core.afg)
+		return true;
+
 	for (n = 0; n < spec->paths.used; n++) {
 		struct nid_path *path = snd_array_elem(&spec->paths, n);
 		if (!path->active)
 			continue;
+		if (codec->power_save_node) {
+			if (!path->stream_enabled)
+				continue;
+			/* ignore unplugged paths except for DAC/ADC */
+			if (!(path->pin_enabled || path->pin_fixed) &&
+			    type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN)
+				continue;
+		}
 		for (i = 0; i < path->depth; i++) {
 			if (path->path[i] == nid) {
 				if (dir == HDA_OUTPUT || path->idx[i] == idx)
@@ -807,6 +822,44 @@
 	}
 }
 
+/* sync power of each widget in the the given path */
+static hda_nid_t path_power_update(struct hda_codec *codec,
+				   struct nid_path *path,
+				   bool allow_powerdown)
+{
+	hda_nid_t nid, changed = 0;
+	int i, state;
+
+	for (i = 0; i < path->depth; i++) {
+		nid = path->path[i];
+		if (!(get_wcaps(codec, nid) & AC_WCAP_POWER))
+			continue;
+		if (nid == codec->core.afg)
+			continue;
+		if (!allow_powerdown || is_active_nid_for_any(codec, nid))
+			state = AC_PWRST_D0;
+		else
+			state = AC_PWRST_D3;
+		if (!snd_hda_check_power_state(codec, nid, state)) {
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_POWER_STATE, state);
+			changed = nid;
+			if (state == AC_PWRST_D0)
+				snd_hdac_regmap_sync_node(&codec->core, nid);
+		}
+	}
+	return changed;
+}
+
+/* do sync with the last power state change */
+static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
+{
+	if (nid) {
+		msleep(10);
+		snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+	}
+}
+
 /**
  * snd_hda_activate_path - activate or deactivate the given path
  * @codec: the HDA codec
@@ -825,15 +878,13 @@
 	if (!enable)
 		path->active = false;
 
+	/* make sure the widget is powered up */
+	if (enable && (spec->power_down_unused || codec->power_save_node))
+		path_power_update(codec, path, codec->power_save_node);
+
 	for (i = path->depth - 1; i >= 0; i--) {
 		hda_nid_t nid = path->path[i];
-		if (enable && spec->power_down_unused) {
-			/* make sure the widget is powered up */
-			if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0))
-				snd_hda_codec_write(codec, nid, 0,
-						    AC_VERB_SET_POWER_STATE,
-						    AC_PWRST_D0);
-		}
+
 		if (enable && path->multi[i])
 			snd_hda_codec_update_cache(codec, nid, 0,
 					    AC_VERB_SET_CONNECT_SEL,
@@ -853,28 +904,10 @@
 static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
 {
 	struct hda_gen_spec *spec = codec->spec;
-	bool changed = false;
-	int i;
 
-	if (!spec->power_down_unused || path->active)
+	if (!(spec->power_down_unused || codec->power_save_node) || path->active)
 		return;
-
-	for (i = 0; i < path->depth; i++) {
-		hda_nid_t nid = path->path[i];
-		if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3) &&
-		    !is_active_nid_for_any(codec, nid)) {
-			snd_hda_codec_write(codec, nid, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			changed = true;
-		}
-	}
-
-	if (changed) {
-		msleep(10);
-		snd_hda_codec_read(codec, path->path[0], 0,
-				   AC_VERB_GET_POWER_STATE, 0);
-	}
+	sync_power_state_change(codec, path_power_update(codec, path, true));
 }
 
 /* turn on/off EAPD on the given pin */
@@ -1574,6 +1607,7 @@
 		return 0;
 	/* print_nid_path(codec, "output-aamix", path); */
 	path->active = false; /* unused as default */
+	path->pin_fixed = true; /* static route */
 	return snd_hda_get_path_idx(codec, path);
 }
 
@@ -1863,12 +1897,11 @@
 static void fill_all_dac_nids(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec = codec->spec;
-	int i;
-	hda_nid_t nid = codec->start_nid;
+	hda_nid_t nid;
 
 	spec->num_all_dacs = 0;
 	memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
 			continue;
 		if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
@@ -2998,6 +3031,7 @@
 	}
 
 	path->active = true;
+	path->stream_enabled = true; /* no DAC/ADC involved */
 	err = add_loopback_list(spec, mix_nid, idx);
 	if (err < 0)
 		return err;
@@ -3009,6 +3043,8 @@
 		if (path) {
 			print_nid_path(codec, "loopback-merge", path);
 			path->active = true;
+			path->pin_fixed = true; /* static route */
+			path->stream_enabled = true; /* no DAC/ADC involved */
 			spec->loopback_merge_path =
 				snd_hda_get_path_idx(codec, path);
 		}
@@ -3030,10 +3066,9 @@
 	hda_nid_t nid;
 	hda_nid_t *adc_nids = spec->adc_nids;
 	int max_nums = ARRAY_SIZE(spec->adc_nids);
-	int i, nums = 0;
+	int nums = 0;
 
-	nid = codec->start_nid;
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		unsigned int caps = get_wcaps(codec, nid);
 		int type = get_wcaps_type(caps);
 
@@ -3346,11 +3381,6 @@
 	imux = &spec->input_mux;
 	adc_idx = kcontrol->id.index;
 	mutex_lock(&codec->control_mutex);
-	/* we use the cache-only update at first since multiple input paths
-	 * may shared the same amp; by updating only caches, the redundant
-	 * writes to hardware can be reduced.
-	 */
-	codec->cached_write = 1;
 	for (i = 0; i < imux->num_items; i++) {
 		path = get_input_path(codec, adc_idx, i);
 		if (!path || !path->ctls[type])
@@ -3358,12 +3388,9 @@
 		kcontrol->private_value = path->ctls[type];
 		err = func(kcontrol, ucontrol);
 		if (err < 0)
-			goto error;
+			break;
 	}
- error:
-	codec->cached_write = 0;
 	mutex_unlock(&codec->control_mutex);
-	snd_hda_codec_flush_cache(codec); /* flush the updates */
 	if (err >= 0 && spec->cap_sync_hook)
 		spec->cap_sync_hook(codec, kcontrol, ucontrol);
 	return err;
@@ -3810,6 +3837,7 @@
 			continue;
 		print_nid_path(codec, "digout", path);
 		path->active = true;
+		path->pin_fixed = true; /* no jack detection */
 		spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
 		set_pin_target(codec, pin, PIN_OUT, false);
 		if (!nums) {
@@ -3826,8 +3854,7 @@
 
 	if (spec->autocfg.dig_in_pin) {
 		pin = spec->autocfg.dig_in_pin;
-		dig_nid = codec->start_nid;
-		for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
+		for_each_hda_codec_node(dig_nid, codec) {
 			unsigned int wcaps = get_wcaps(codec, dig_nid);
 			if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
 				continue;
@@ -3837,6 +3864,7 @@
 			if (path) {
 				print_nid_path(codec, "digin", path);
 				path->active = true;
+				path->pin_fixed = true; /* no jack */
 				spec->dig_in_nid = dig_nid;
 				spec->digin_path = snd_hda_get_path_idx(codec, path);
 				set_pin_target(codec, pin, PIN_IN, false);
@@ -3896,6 +3924,238 @@
 	return 1;
 }
 
+/* power up/down widgets in the all paths that match with the given NID
+ * as terminals (either start- or endpoint)
+ *
+ * returns the last changed NID, or zero if unchanged.
+ */
+static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid,
+				int pin_state, int stream_state)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	hda_nid_t last, changed = 0;
+	struct nid_path *path;
+	int n;
+
+	for (n = 0; n < spec->paths.used; n++) {
+		path = snd_array_elem(&spec->paths, n);
+		if (path->path[0] == nid ||
+		    path->path[path->depth - 1] == nid) {
+			bool pin_old = path->pin_enabled;
+			bool stream_old = path->stream_enabled;
+
+			if (pin_state >= 0)
+				path->pin_enabled = pin_state;
+			if (stream_state >= 0)
+				path->stream_enabled = stream_state;
+			if ((!path->pin_fixed && path->pin_enabled != pin_old)
+			    || path->stream_enabled != stream_old) {
+				last = path_power_update(codec, path, true);
+				if (last)
+					changed = last;
+			}
+		}
+	}
+	return changed;
+}
+
+/* check the jack status for power control */
+static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin)
+{
+	if (!is_jack_detectable(codec, pin))
+		return true;
+	return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
+}
+
+/* power up/down the paths of the given pin according to the jack state;
+ * power = 0/1 : only power up/down if it matches with the jack state,
+ *       < 0   : force power up/down to follow the jack sate
+ *
+ * returns the last changed NID, or zero if unchanged.
+ */
+static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin,
+				    int power)
+{
+	bool on;
+
+	if (!codec->power_save_node)
+		return 0;
+
+	on = detect_pin_state(codec, pin);
+
+	if (power >= 0 && on != power)
+		return 0;
+	return set_path_power(codec, pin, on, -1);
+}
+
+static void pin_power_callback(struct hda_codec *codec,
+			       struct hda_jack_callback *jack,
+			       bool on)
+{
+	if (jack && jack->tbl->nid)
+		sync_power_state_change(codec,
+					set_pin_power_jack(codec, jack->tbl->nid, on));
+}
+
+/* callback only doing power up -- called at first */
+static void pin_power_up_callback(struct hda_codec *codec,
+				  struct hda_jack_callback *jack)
+{
+	pin_power_callback(codec, jack, true);
+}
+
+/* callback only doing power down -- called at last */
+static void pin_power_down_callback(struct hda_codec *codec,
+				    struct hda_jack_callback *jack)
+{
+	pin_power_callback(codec, jack, false);
+}
+
+/* set up the power up/down callbacks */
+static void add_pin_power_ctls(struct hda_codec *codec, int num_pins,
+			       const hda_nid_t *pins, bool on)
+{
+	int i;
+	hda_jack_callback_fn cb =
+		on ? pin_power_up_callback : pin_power_down_callback;
+
+	for (i = 0; i < num_pins && pins[i]; i++) {
+		if (is_jack_detectable(codec, pins[i]))
+			snd_hda_jack_detect_enable_callback(codec, pins[i], cb);
+		else
+			set_path_power(codec, pins[i], true, -1);
+	}
+}
+
+/* enabled power callback to each available I/O pin with jack detections;
+ * the digital I/O pins are excluded because of the unreliable detectsion
+ */
+static void add_all_pin_power_ctls(struct hda_codec *codec, bool on)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+
+	if (!codec->power_save_node)
+		return;
+	add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on);
+	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+		add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on);
+	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+		add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on);
+	for (i = 0; i < cfg->num_inputs; i++)
+		add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on);
+}
+
+/* sync path power up/down with the jack states of given pins */
+static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins,
+				const hda_nid_t *pins)
+{
+	int i;
+
+	for (i = 0; i < num_pins && pins[i]; i++)
+		if (is_jack_detectable(codec, pins[i]))
+			set_pin_power_jack(codec, pins[i], -1);
+}
+
+/* sync path power up/down with pins; called at init and resume */
+static void sync_all_pin_power_ctls(struct hda_codec *codec)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+
+	if (!codec->power_save_node)
+		return;
+	sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins);
+	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+		sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins);
+	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+		sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins);
+	for (i = 0; i < cfg->num_inputs; i++)
+		sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
+}
+
+/* add fake paths if not present yet */
+static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
+			   int num_pins, const hda_nid_t *pins)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct nid_path *path;
+	int i;
+
+	for (i = 0; i < num_pins; i++) {
+		if (!pins[i])
+			break;
+		if (get_nid_path(codec, nid, pins[i], 0))
+			continue;
+		path = snd_array_new(&spec->paths);
+		if (!path)
+			return -ENOMEM;
+		memset(path, 0, sizeof(*path));
+		path->depth = 2;
+		path->path[0] = nid;
+		path->path[1] = pins[i];
+		path->active = true;
+	}
+	return 0;
+}
+
+/* create fake paths to all outputs from beep */
+static int add_fake_beep_paths(struct hda_codec *codec)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	hda_nid_t nid = spec->beep_nid;
+	int err;
+
+	if (!codec->power_save_node || !nid)
+		return 0;
+	err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
+	if (err < 0)
+		return err;
+	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+		err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
+		if (err < 0)
+			return err;
+	}
+	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+		err = add_fake_paths(codec, nid, cfg->speaker_outs,
+				     cfg->speaker_pins);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* power up/down beep widget and its output paths */
+static void beep_power_hook(struct hda_beep *beep, bool on)
+{
+	set_path_power(beep->codec, beep->nid, -1, on);
+}
+
+/**
+ * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0
+ * @codec: the HDA codec
+ * @pin: NID of pin to fix
+ */
+int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct nid_path *path;
+
+	path = snd_array_new(&spec->paths);
+	if (!path)
+		return -ENOMEM;
+	memset(path, 0, sizeof(*path));
+	path->depth = 1;
+	path->path[0] = pin;
+	path->active = true;
+	path->pin_fixed = true;
+	path->stream_enabled = true;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power);
 
 /*
  * Jack detections for HP auto-mute and mic-switch
@@ -3933,6 +4193,10 @@
 		if (!nid)
 			break;
 
+		oldval = snd_hda_codec_get_pin_target(codec, nid);
+		if (oldval & PIN_IN)
+			continue; /* no mute for inputs */
+
 		if (spec->auto_mute_via_amp) {
 			struct nid_path *path;
 			hda_nid_t mute_nid;
@@ -3947,29 +4211,32 @@
 				spec->mute_bits |= (1ULL << mute_nid);
 			else
 				spec->mute_bits &= ~(1ULL << mute_nid);
-			set_pin_eapd(codec, nid, !mute);
 			continue;
+		} else {
+			/* don't reset VREF value in case it's controlling
+			 * the amp (see alc861_fixup_asus_amp_vref_0f())
+			 */
+			if (spec->keep_vref_in_automute)
+				val = oldval & ~PIN_HP;
+			else
+				val = 0;
+			if (!mute)
+				val |= oldval;
+			/* here we call update_pin_ctl() so that the pinctl is
+			 * changed without changing the pinctl target value;
+			 * the original target value will be still referred at
+			 * the init / resume again
+			 */
+			update_pin_ctl(codec, nid, val);
 		}
 
-		oldval = snd_hda_codec_get_pin_target(codec, nid);
-		if (oldval & PIN_IN)
-			continue; /* no mute for inputs */
-		/* don't reset VREF value in case it's controlling
-		 * the amp (see alc861_fixup_asus_amp_vref_0f())
-		 */
-		if (spec->keep_vref_in_automute)
-			val = oldval & ~PIN_HP;
-		else
-			val = 0;
-		if (!mute)
-			val |= oldval;
-		/* here we call update_pin_ctl() so that the pinctl is changed
-		 * without changing the pinctl target value;
-		 * the original target value will be still referred at the
-		 * init / resume again
-		 */
-		update_pin_ctl(codec, nid, val);
 		set_pin_eapd(codec, nid, !mute);
+		if (codec->power_save_node) {
+			bool on = !mute;
+			if (on)
+				on = detect_pin_state(codec, nid);
+			set_path_power(codec, nid, on, -1);
+		}
 	}
 }
 
@@ -4436,7 +4703,11 @@
 						  hda_nid_t nid,
 						  unsigned int power_state)
 {
-	if (power_state != AC_PWRST_D0 || nid == codec->afg)
+	struct hda_gen_spec *spec = codec->spec;
+
+	if (!spec->power_down_unused && !codec->power_save_node)
+		return power_state;
+	if (power_state != AC_PWRST_D0 || nid == codec->core.afg)
 		return power_state;
 	if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
 		return power_state;
@@ -4466,6 +4737,21 @@
 }
 
 /**
+ * snd_hda_gen_stream_pm - Stream power management callback
+ * @codec: the HDA codec
+ * @nid: audio widget
+ * @on: power on/off flag
+ *
+ * Set this in patch_ops.stream_pm.  Only valid with power_save_node flag.
+ */
+void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
+{
+	if (codec->power_save_node)
+		set_path_power(codec, nid, -1, on);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
+
+/**
  * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
  * set up the hda_gen_spec
  * @codec: the HDA codec
@@ -4549,6 +4835,9 @@
 	if (err < 0)
 		return err;
 
+	/* add power-down pin callbacks at first */
+	add_all_pin_power_ctls(codec, false);
+
 	spec->const_channel_count = spec->ext_channel_count;
 	/* check the multiple speaker and headphone pins */
 	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
@@ -4618,6 +4907,9 @@
 		}
 	}
 
+	/* add power-up pin callbacks at last */
+	add_all_pin_power_ctls(codec, true);
+
 	/* mute all aamix input initially */
 	if (spec->mixer_nid)
 		mute_all_mixer_nid(codec, spec->mixer_nid);
@@ -4625,13 +4917,20 @@
  dig_only:
 	parse_digital(codec);
 
-	if (spec->power_down_unused)
-		codec->power_filter = snd_hda_gen_path_power_filter;
+	if (spec->power_down_unused || codec->power_save_node)
+		if (!codec->power_filter)
+			codec->power_filter = snd_hda_gen_path_power_filter;
 
 	if (!spec->no_analog && spec->beep_nid) {
 		err = snd_hda_attach_beep_device(codec, spec->beep_nid);
 		if (err < 0)
 			return err;
+		if (codec->beep && codec->power_save_node) {
+			err = add_fake_beep_paths(codec);
+			if (err < 0)
+				return err;
+			codec->beep->power_hook = beep_power_hook;
+		}
 	}
 
 	return 1;
@@ -4675,7 +4974,7 @@
 		err = snd_hda_create_dig_out_ctls(codec,
 						  spec->multiout.dig_out_nid,
 						  spec->multiout.dig_out_nid,
-						  spec->pcm_rec[1].pcm_type);
+						  spec->pcm_rec[1]->pcm_type);
 		if (err < 0)
 			return err;
 		if (!spec->no_analog) {
@@ -5137,6 +5436,33 @@
 	strlcat(str, sfx, len);
 }
 
+/* copy PCM stream info from @default_str, and override non-NULL entries
+ * from @spec_str and @nid
+ */
+static void setup_pcm_stream(struct hda_pcm_stream *str,
+			     const struct hda_pcm_stream *default_str,
+			     const struct hda_pcm_stream *spec_str,
+			     hda_nid_t nid)
+{
+	*str = *default_str;
+	if (nid)
+		str->nid = nid;
+	if (spec_str) {
+		if (spec_str->substreams)
+			str->substreams = spec_str->substreams;
+		if (spec_str->channels_min)
+			str->channels_min = spec_str->channels_min;
+		if (spec_str->channels_max)
+			str->channels_max = spec_str->channels_max;
+		if (spec_str->rates)
+			str->rates = spec_str->rates;
+		if (spec_str->formats)
+			str->formats = spec_str->formats;
+		if (spec_str->maxbps)
+			str->maxbps = spec_str->maxbps;
+	}
+}
+
 /**
  * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
  * @codec: the HDA codec
@@ -5146,27 +5472,25 @@
 int snd_hda_gen_build_pcms(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec = codec->spec;
-	struct hda_pcm *info = spec->pcm_rec;
-	const struct hda_pcm_stream *p;
+	struct hda_pcm *info;
 	bool have_multi_adcs;
 
-	codec->num_pcms = 1;
-	codec->pcm_info = info;
-
 	if (spec->no_analog)
 		goto skip_analog;
 
 	fill_pcm_stream_name(spec->stream_name_analog,
 			     sizeof(spec->stream_name_analog),
-			     " Analog", codec->chip_name);
-	info->name = spec->stream_name_analog;
+			     " Analog", codec->core.chip_name);
+	info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
+	if (!info)
+		return -ENOMEM;
+	spec->pcm_rec[0] = info;
 
 	if (spec->multiout.num_dacs > 0) {
-		p = spec->stream_analog_playback;
-		if (!p)
-			p = &pcm_analog_playback;
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+		setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+				 &pcm_analog_playback,
+				 spec->stream_analog_playback,
+				 spec->multiout.dac_nids[0]);
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
 			spec->multiout.max_channels;
 		if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
@@ -5175,15 +5499,11 @@
 				snd_pcm_2_1_chmaps;
 	}
 	if (spec->num_adc_nids) {
-		p = spec->stream_analog_capture;
-		if (!p) {
-			if (spec->dyn_adc_switch)
-				p = &dyn_adc_pcm_analog_capture;
-			else
-				p = &pcm_analog_capture;
-		}
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
-		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+		setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+				 (spec->dyn_adc_switch ?
+				  &dyn_adc_pcm_analog_capture : &pcm_analog_capture),
+				 spec->stream_analog_capture,
+				 spec->adc_nids[0]);
 	}
 
  skip_analog:
@@ -5191,29 +5511,27 @@
 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
 		fill_pcm_stream_name(spec->stream_name_digital,
 				     sizeof(spec->stream_name_digital),
-				     " Digital", codec->chip_name);
-		codec->num_pcms = 2;
+				     " Digital", codec->core.chip_name);
+		info = snd_hda_codec_pcm_new(codec, "%s",
+					     spec->stream_name_digital);
+		if (!info)
+			return -ENOMEM;
 		codec->slave_dig_outs = spec->multiout.slave_dig_outs;
-		info = spec->pcm_rec + 1;
-		info->name = spec->stream_name_digital;
+		spec->pcm_rec[1] = info;
 		if (spec->dig_out_type)
 			info->pcm_type = spec->dig_out_type;
 		else
 			info->pcm_type = HDA_PCM_TYPE_SPDIF;
-		if (spec->multiout.dig_out_nid) {
-			p = spec->stream_digital_playback;
-			if (!p)
-				p = &pcm_digital_playback;
-			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
-			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
-		}
-		if (spec->dig_in_nid) {
-			p = spec->stream_digital_capture;
-			if (!p)
-				p = &pcm_digital_capture;
-			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
-			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
-		}
+		if (spec->multiout.dig_out_nid)
+			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+					 &pcm_digital_playback,
+					 spec->stream_digital_playback,
+					 spec->multiout.dig_out_nid);
+		if (spec->dig_in_nid)
+			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+					 &pcm_digital_capture,
+					 spec->stream_digital_capture,
+					 spec->dig_in_nid);
 	}
 
 	if (spec->no_analog)
@@ -5228,35 +5546,30 @@
 	if (spec->alt_dac_nid || have_multi_adcs) {
 		fill_pcm_stream_name(spec->stream_name_alt_analog,
 				     sizeof(spec->stream_name_alt_analog),
-			     " Alt Analog", codec->chip_name);
-		codec->num_pcms = 3;
-		info = spec->pcm_rec + 2;
-		info->name = spec->stream_name_alt_analog;
-		if (spec->alt_dac_nid) {
-			p = spec->stream_analog_alt_playback;
-			if (!p)
-				p = &pcm_analog_alt_playback;
-			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
-			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
-				spec->alt_dac_nid;
-		} else {
-			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-				pcm_null_stream;
-			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
-		}
+			     " Alt Analog", codec->core.chip_name);
+		info = snd_hda_codec_pcm_new(codec, "%s",
+					     spec->stream_name_alt_analog);
+		if (!info)
+			return -ENOMEM;
+		spec->pcm_rec[2] = info;
+		if (spec->alt_dac_nid)
+			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+					 &pcm_analog_alt_playback,
+					 spec->stream_analog_alt_playback,
+					 spec->alt_dac_nid);
+		else
+			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+					 &pcm_null_stream, NULL, 0);
 		if (have_multi_adcs) {
-			p = spec->stream_analog_alt_capture;
-			if (!p)
-				p = &pcm_analog_alt_capture;
-			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
-			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
-				spec->adc_nids[1];
+			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+					 &pcm_analog_alt_capture,
+					 spec->stream_analog_alt_capture,
+					 spec->adc_nids[1]);
 			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
 				spec->num_adc_nids - 1;
 		} else {
-			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-				pcm_null_stream;
-			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
+			setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+					 &pcm_null_stream, NULL, 0);
 		}
 	}
 
@@ -5452,8 +5765,6 @@
 
 	snd_hda_apply_verbs(codec);
 
-	codec->cached_write = 1;
-
 	init_multi_out(codec);
 	init_extra_out(codec);
 	init_multi_io(codec);
@@ -5464,10 +5775,12 @@
 
 	clear_unsol_on_unused_pins(codec);
 
+	sync_all_pin_power_ctls(codec);
+
 	/* call init functions of standard auto-mute helpers */
 	update_automute_all(codec);
 
-	snd_hda_codec_flush_cache(codec);
+	regcache_sync(codec->core.regmap);
 
 	if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
 		snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
@@ -5524,13 +5837,11 @@
 #endif
 };
 
-/**
+/*
  * snd_hda_parse_generic_codec - Generic codec parser
  * @codec: the HDA codec
- *
- * This should be called from the HDA codec core.
  */
-int snd_hda_parse_generic_codec(struct hda_codec *codec)
+static int snd_hda_parse_generic_codec(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec;
 	int err;
@@ -5556,7 +5867,17 @@
 	snd_hda_gen_free(codec);
 	return err;
 }
-EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec);
+
+static const struct hda_codec_preset snd_hda_preset_generic[] = {
+	{ .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec },
+	{} /* terminator */
+};
+
+static struct hda_codec_driver generic_driver = {
+	.preset = snd_hda_preset_generic,
+};
+
+module_hda_codec_driver(generic_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic HD-audio codec parser");
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 3d85266..56e4139 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -46,7 +46,10 @@
 	unsigned char idx[MAX_NID_PATH_DEPTH];
 	unsigned char multi[MAX_NID_PATH_DEPTH];
 	unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
-	bool active;
+	bool active:1;		/* activated by driver */
+	bool pin_enabled:1;	/* pins are enabled */
+	bool pin_fixed:1;	/* path with fixed pin */
+	bool stream_enabled:1;	/* stream is active */
 };
 
 /* mic/line-in auto switching entry */
@@ -144,7 +147,7 @@
 	int const_channel_count;	/* channel count for all */
 
 	/* PCM information */
-	struct hda_pcm pcm_rec[3];	/* used in build_pcms() */
+	struct hda_pcm *pcm_rec[3];	/* used in build_pcms() */
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
@@ -340,5 +343,7 @@
 unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
 					   hda_nid_t nid,
 					   unsigned int power_state);
+void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
+int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
 
 #endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 11b5a42..57df06e 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -101,7 +101,7 @@
 	int err;
 
 	sprintf(hwname, "HDA Codec %d", codec->addr);
-	err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep);
+	err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep);
 	if (err < 0)
 		return err;
 	codec->hwdep = hwdep;
@@ -116,9 +116,6 @@
 	hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
 #endif
 
-	/* link to codec */
-	hwdep->dev.parent = &codec->dev;
-
 	/* for sysfs */
 	hwdep->dev.groups = snd_hda_dev_attr_groups;
 	dev_set_drvdata(&hwdep->dev, codec);
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c
index 7148945..52a85d8 100644
--- a/sound/pci/hda/hda_i915.c
+++ b/sound/pci/hda/hda_i915.c
@@ -22,7 +22,7 @@
 #include <linux/component.h>
 #include <drm/i915_component.h>
 #include <sound/core.h>
-#include "hda_priv.h"
+#include "hda_controller.h"
 #include "hda_intel.h"
 
 /* Intel HSW/BDW display HDA controller Extended Mode registers.
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index a8a1e14..e1c2105 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -62,7 +62,6 @@
 #include <linux/firmware.h>
 #include "hda_codec.h"
 #include "hda_controller.h"
-#include "hda_priv.h"
 #include "hda_intel.h"
 
 /* position fix mode */
@@ -174,7 +173,6 @@
 #define param_check_xint param_check_int
 
 static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-static int *power_save_addr = &power_save;
 module_param(power_save, xint, 0644);
 MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
 		 "(in second, 0 = disable).");
@@ -187,7 +185,7 @@
 module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #else
-static int *power_save_addr;
+#define power_save	0
 #endif /* CONFIG_PM */
 
 static int align_buffer_size = -1;
@@ -299,8 +297,12 @@
 	 AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
 	 AZX_DCAPS_SNOOP_TYPE(SCH))
 
+#define AZX_DCAPS_INTEL_BRASWELL \
+	(AZX_DCAPS_INTEL_PCH | AZX_DCAPS_I915_POWERWELL)
+
 #define AZX_DCAPS_INTEL_SKYLAKE \
-	(AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG)
+	(AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\
+	 AZX_DCAPS_I915_POWERWELL)
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -530,10 +532,10 @@
 	if (ok == 1) {
 		azx_dev->irq_pending = 0;
 		return ok;
-	} else if (ok == 0 && chip->bus && chip->bus->workq) {
+	} else if (ok == 0) {
 		/* bogus IRQ, process it later */
 		azx_dev->irq_pending = 1;
-		queue_work(chip->bus->workq, &hda->irq_pending_work);
+		schedule_work(&hda->irq_pending_work);
 	}
 	return 0;
 }
@@ -741,7 +743,6 @@
 {
 	struct hda_intel *hda;
 	struct azx *chip;
-	struct hda_codec *c;
 	int prev = power_save;
 	int ret = param_set_int(val, kp);
 
@@ -753,8 +754,7 @@
 		chip = &hda->chip;
 		if (!chip->bus || chip->disabled)
 			continue;
-		list_for_each_entry(c, &chip->bus->codec_list, list)
-			snd_hda_power_sync(c);
+		snd_hda_set_power_save(chip->bus, power_save * 1000);
 	}
 	mutex_unlock(&card_list_lock);
 	return 0;
@@ -773,7 +773,6 @@
 	struct snd_card *card = dev_get_drvdata(dev);
 	struct azx *chip;
 	struct hda_intel *hda;
-	struct azx_pcm *p;
 
 	if (!card)
 		return 0;
@@ -785,10 +784,6 @@
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	azx_clear_irq_pending(chip);
-	list_for_each_entry(p, &chip->pcm_list, list)
-		snd_pcm_suspend_all(p->pcm);
-	if (chip->initialized)
-		snd_hda_suspend(chip->bus);
 	azx_stop_chip(chip);
 	azx_enter_link_reset(chip);
 	if (chip->irq >= 0) {
@@ -831,7 +826,6 @@
 
 	azx_init_chip(chip, true);
 
-	snd_hda_resume(chip->bus);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
@@ -852,7 +846,7 @@
 	if (chip->disabled || hda->init_failed)
 		return 0;
 
-	if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+	if (!azx_has_pm_runtime(chip))
 		return 0;
 
 	/* enable controller wake up event */
@@ -885,7 +879,7 @@
 	if (chip->disabled || hda->init_failed)
 		return 0;
 
-	if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+	if (!azx_has_pm_runtime(chip))
 		return 0;
 
 	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
@@ -901,10 +895,10 @@
 
 	bus = chip->bus;
 	if (status && bus) {
-		list_for_each_entry(codec, &bus->codec_list, list)
+		list_for_each_codec(codec, bus)
 			if (status & (1 << codec->addr))
-				queue_delayed_work(codec->bus->workq,
-						   &codec->jackpoll_work, codec->jackpoll_interval);
+				schedule_delayed_work(&codec->jackpoll_work,
+						      codec->jackpoll_interval);
 	}
 
 	/* disable controller Wake Up event*/
@@ -928,8 +922,8 @@
 	if (chip->disabled || hda->init_failed)
 		return 0;
 
-	if (!power_save_controller ||
-	    !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+	if (!power_save_controller || !azx_has_pm_runtime(chip) ||
+	    chip->bus->core.codec_powered)
 		return -EBUSY;
 
 	return 0;
@@ -1071,14 +1065,11 @@
 	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
 	int i;
 
-	if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
-			&& chip->running)
+	if (azx_has_pm_runtime(chip) && chip->running)
 		pm_runtime_get_noresume(&pci->dev);
 
 	azx_del_card_list(chip);
 
-	azx_notifier_unregister(chip);
-
 	hda->init_failed = 1; /* to be sure */
 	complete_all(&hda->probe_wait);
 
@@ -1394,7 +1385,6 @@
 
 	hda = kzalloc(sizeof(*hda), GFP_KERNEL);
 	if (!hda) {
-		dev_err(card->dev, "Cannot allocate hda\n");
 		pci_disable_device(pci);
 		return -ENOMEM;
 	}
@@ -1575,10 +1565,8 @@
 	chip->num_streams = chip->playback_streams + chip->capture_streams;
 	chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
 				GFP_KERNEL);
-	if (!chip->azx_dev) {
-		dev_err(card->dev, "cannot malloc azx_dev\n");
+	if (!chip->azx_dev)
 		return -ENOMEM;
-	}
 
 	err = azx_alloc_stream_pages(chip);
 	if (err < 0)
@@ -1615,19 +1603,6 @@
 	return 0;
 }
 
-static void power_down_all_codecs(struct azx *chip)
-{
-#ifdef CONFIG_PM
-	/* The codecs were powered up in snd_hda_codec_new().
-	 * Now all initialization done, so turn them down if possible
-	 */
-	struct hda_codec *codec;
-	list_for_each_entry(codec, &chip->bus->codec_list, list) {
-		snd_hda_power_down(codec);
-	}
-#endif
-}
-
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 /* callback from request_firmware_nowait() */
 static void azx_firmware_cb(const struct firmware *fw, void *context)
@@ -1896,12 +1871,14 @@
 #endif
 
 	/* create codec instances */
-	err = azx_codec_create(chip, model[dev],
-			       azx_max_codecs[chip->driver_type],
-			       power_save_addr);
-
+	err = azx_bus_create(chip, model[dev]);
 	if (err < 0)
 		goto out_free;
+
+	err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);
+	if (err < 0)
+		goto out_free;
+
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 	if (chip->fw) {
 		err = snd_hda_load_patch(chip->bus, chip->fw->size,
@@ -1920,25 +1897,14 @@
 			goto out_free;
 	}
 
-	/* create PCM streams */
-	err = snd_hda_build_pcms(chip->bus);
-	if (err < 0)
-		goto out_free;
-
-	/* create mixer controls */
-	err = azx_mixer_create(chip);
-	if (err < 0)
-		goto out_free;
-
 	err = snd_card_register(chip->card);
 	if (err < 0)
 		goto out_free;
 
 	chip->running = 1;
-	power_down_all_codecs(chip);
-	azx_notifier_register(chip);
 	azx_add_card_list(chip);
-	if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || hda->use_vga_switcheroo)
+	snd_hda_set_power_save(chip->bus, power_save * 1000);
+	if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
 		pm_runtime_put_noidle(&pci->dev);
 
 out_free:
@@ -1956,6 +1922,18 @@
 		snd_card_free(card);
 }
 
+static void azx_shutdown(struct pci_dev *pci)
+{
+	struct snd_card *card = pci_get_drvdata(pci);
+	struct azx *chip;
+
+	if (!card)
+		return;
+	chip = card->private_data;
+	if (chip && chip->running)
+		azx_stop_chip(chip);
+}
+
 /* PCI IDs */
 static const struct pci_device_id azx_ids[] = {
 	/* CPT */
@@ -2017,7 +1995,7 @@
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
 	/* Braswell */
 	{ PCI_DEVICE(0x8086, 0x2284),
-	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL },
 	/* ICH6 */
 	{ PCI_DEVICE(0x8086, 0x2668),
 	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
@@ -2178,6 +2156,7 @@
 	.id_table = azx_ids,
 	.probe = azx_probe,
 	.remove = azx_remove,
+	.shutdown = azx_shutdown,
 	.driver = {
 		.pm = AZX_PM_OPS,
 	},
diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
index 3486118..d5231f7 100644
--- a/sound/pci/hda/hda_intel.h
+++ b/sound/pci/hda/hda_intel.h
@@ -17,7 +17,7 @@
 #define __SOUND_HDA_INTEL_H
 
 #include <drm/i915_component.h>
-#include "hda_priv.h"
+#include "hda_controller.h"
 
 struct hda_intel {
 	struct azx chip;
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index e664307..d7cfe7b 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -135,7 +135,7 @@
 #ifdef CONFIG_SND_HDA_INPUT_JACK
 		/* free jack instances manually when clearing/reconfiguring */
 		if (!codec->bus->shutdown && jack->jack)
-			snd_device_free(codec->bus->card, jack->jack);
+			snd_device_free(codec->card, jack->jack);
 #endif
 		for (cb = jack->callback; cb; cb = next) {
 			next = cb->next;
@@ -340,7 +340,7 @@
 			if (!jack->kctl || jack->block_report)
 				continue;
 			state = get_jack_plug_state(jack->pin_sense);
-			snd_kctl_jack_report(codec->bus->card, jack->kctl, state);
+			snd_kctl_jack_report(codec->card, jack->kctl, state);
 #ifdef CONFIG_SND_HDA_INPUT_JACK
 			if (jack->jack)
 				snd_jack_report(jack->jack,
@@ -412,11 +412,11 @@
 	jack->phantom_jack = !!phantom_jack;
 
 	state = snd_hda_jack_detect(codec, nid);
-	snd_kctl_jack_report(codec->bus->card, kctl, state);
+	snd_kctl_jack_report(codec->card, kctl, state);
 #ifdef CONFIG_SND_HDA_INPUT_JACK
 	if (!phantom_jack) {
 		jack->type = get_input_jack_type(codec, nid);
-		err = snd_jack_new(codec->bus->card, name, jack->type,
+		err = snd_jack_new(codec->card, name, jack->type,
 				   &jack->jack);
 		if (err < 0)
 			return err;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 62658f2..3b567f4 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -127,18 +127,16 @@
 				      struct snd_ctl_elem_value *ucontrol);
 #endif
 /* lowlevel accessor with caching; use carefully */
-int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
-			   int direction, int index);
-int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
-			     int direction, int idx, int mask, int val);
+#define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \
+	snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx)
+#define snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val) \
+	snd_hdac_regmap_update_amp(&(codec)->core, nid, ch, dir, idx, mask, val)
 int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
 			     int dir, int idx, int mask, int val);
 int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
 			   int direction, int idx, int mask, int val);
 int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
 				  int dir, int idx, int mask, int val);
-void snd_hda_codec_resume_amp(struct hda_codec *codec);
-
 void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
 			     unsigned int *tlv);
 struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
@@ -150,6 +148,8 @@
 #define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
 	__snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
 int snd_hda_codec_reset(struct hda_codec *codec);
+void snd_hda_codec_register(struct hda_codec *codec);
+void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
 
 enum {
 	HDA_VMUTE_OFF,
@@ -273,29 +273,6 @@
 			  int index, int *type_index_ret);
 
 /*
- * Channel mode helper
- */
-struct hda_channel_mode {
-	int channels;
-	const struct hda_verb *sequence;
-};
-
-int snd_hda_ch_mode_info(struct hda_codec *codec,
-			 struct snd_ctl_elem_info *uinfo,
-			 const struct hda_channel_mode *chmode,
-			 int num_chmodes);
-int snd_hda_ch_mode_get(struct hda_codec *codec,
-			struct snd_ctl_elem_value *ucontrol,
-			const struct hda_channel_mode *chmode,
-			int num_chmodes,
-			int max_channels);
-int snd_hda_ch_mode_put(struct hda_codec *codec,
-			struct snd_ctl_elem_value *ucontrol,
-			const struct hda_channel_mode *chmode,
-			int num_chmodes,
-			int *max_channelsp);
-
-/*
  * Multi-channel / digital-out PCM helper
  */
 
@@ -351,12 +328,6 @@
 				     struct hda_multi_out *mout);
 
 /*
- * generic codec parser
- */
-int snd_hda_parse_generic_codec(struct hda_codec *codec);
-int snd_hda_parse_hdmi_codec(struct hda_codec *codec);
-
-/*
  * generic proc interface
  */
 #ifdef CONFIG_PROC_FS
@@ -466,23 +437,6 @@
 			    const struct snd_hda_pin_quirk *pin_quirk,
 			    const struct hda_fixup *fixlist);
 
-
-/*
- * unsolicited event handler
- */
-
-#define HDA_UNSOL_QUEUE_SIZE	64
-
-struct hda_bus_unsolicited {
-	/* ring buffer */
-	u32 queue[HDA_UNSOL_QUEUE_SIZE * 2];
-	unsigned int rp, wp;
-
-	/* workqueue */
-	struct work_struct work;
-	struct hda_bus *bus;
-};
-
 /* helper macros to retrieve pin default-config values */
 #define get_defcfg_connect(cfg) \
 	((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
@@ -560,15 +514,18 @@
 int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
 				 unsigned int val);
 
+#define for_each_hda_codec_node(nid, codec) \
+	for ((nid) = (codec)->core.start_nid; (nid) < (codec)->core.end_nid; (nid)++)
+
 /*
  * get widget capabilities
  */
 static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
 {
-	if (nid < codec->start_nid ||
-	    nid >= codec->start_nid + codec->num_nodes)
+	if (nid < codec->core.start_nid ||
+	    nid >= codec->core.start_nid + codec->core.num_nodes)
 		return 0;
-	return codec->wcaps[nid - codec->start_nid];
+	return codec->wcaps[nid - codec->core.start_nid];
 }
 
 /* get the widget type from widget capability bits */
@@ -592,17 +549,49 @@
 static inline void snd_hda_override_wcaps(struct hda_codec *codec,
 					  hda_nid_t nid, u32 val)
 {
-	if (nid >= codec->start_nid &&
-	    nid < codec->start_nid + codec->num_nodes)
-		codec->wcaps[nid - codec->start_nid] = val;
+	if (nid >= codec->core.start_nid &&
+	    nid < codec->core.start_nid + codec->core.num_nodes)
+		codec->wcaps[nid - codec->core.start_nid] = val;
 }
 
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps);
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
-			      unsigned int caps);
+/**
+ * snd_hda_query_pin_caps - Query PIN capabilities
+ * @codec: the HD-auio codec
+ * @nid: the NID to query
+ *
+ * Query PIN capabilities for the given widget.
+ * Returns the obtained capability bits.
+ *
+ * When cap bits have been already read, this doesn't read again but
+ * returns the cached value.
+ */
+static inline u32
+snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+
+}
+
+/**
+ * snd_hda_override_pin_caps - Override the pin capabilities
+ * @codec: the CODEC
+ * @nid: the NID to override
+ * @caps: the capability bits to set
+ *
+ * Override the cached PIN capabilitiy bits value by the given one.
+ *
+ * Returns zero if successful or a negative error code.
+ */
+static inline int
+snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
+			  unsigned int caps)
+{
+	return snd_hdac_override_parm(&codec->core, nid, AC_PAR_PIN_CAP, caps);
+}
+
 bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
 			   int dir, unsigned int bits);
 
@@ -800,9 +789,13 @@
 
 /*
  */
-#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args)
-#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args)
-#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args)
-#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args)
+#define codec_err(codec, fmt, args...) \
+	dev_err(hda_codec_dev(codec), fmt, ##args)
+#define codec_warn(codec, fmt, args...) \
+	dev_warn(hda_codec_dev(codec), fmt, ##args)
+#define codec_info(codec, fmt, args...) \
+	dev_info(hda_codec_dev(codec), fmt, ##args)
+#define codec_dbg(codec, fmt, args...) \
+	dev_dbg(hda_codec_dev(codec), fmt, ##args)
 
 #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
deleted file mode 100644
index daf4582..0000000
--- a/sound/pci/hda/hda_priv.h
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- *  Common defines for the alsa driver code base for HD Audio.
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- */
-
-#ifndef __SOUND_HDA_PRIV_H
-#define __SOUND_HDA_PRIV_H
-
-#include <linux/timecounter.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-/*
- * registers
- */
-#define AZX_REG_GCAP			0x00
-#define   AZX_GCAP_64OK		(1 << 0)   /* 64bit address support */
-#define   AZX_GCAP_NSDO		(3 << 1)   /* # of serial data out signals */
-#define   AZX_GCAP_BSS		(31 << 3)  /* # of bidirectional streams */
-#define   AZX_GCAP_ISS		(15 << 8)  /* # of input streams */
-#define   AZX_GCAP_OSS		(15 << 12) /* # of output streams */
-#define AZX_REG_VMIN			0x02
-#define AZX_REG_VMAJ			0x03
-#define AZX_REG_OUTPAY			0x04
-#define AZX_REG_INPAY			0x06
-#define AZX_REG_GCTL			0x08
-#define   AZX_GCTL_RESET	(1 << 0)   /* controller reset */
-#define   AZX_GCTL_FCNTRL	(1 << 1)   /* flush control */
-#define   AZX_GCTL_UNSOL	(1 << 8)   /* accept unsol. response enable */
-#define AZX_REG_WAKEEN			0x0c
-#define AZX_REG_STATESTS		0x0e
-#define AZX_REG_GSTS			0x10
-#define   AZX_GSTS_FSTS		(1 << 1)   /* flush status */
-#define AZX_REG_INTCTL			0x20
-#define AZX_REG_INTSTS			0x24
-#define AZX_REG_WALLCLK			0x30	/* 24Mhz source */
-#define AZX_REG_OLD_SSYNC		0x34	/* SSYNC for old ICH */
-#define AZX_REG_SSYNC			0x38
-#define AZX_REG_CORBLBASE		0x40
-#define AZX_REG_CORBUBASE		0x44
-#define AZX_REG_CORBWP			0x48
-#define AZX_REG_CORBRP			0x4a
-#define   AZX_CORBRP_RST	(1 << 15)  /* read pointer reset */
-#define AZX_REG_CORBCTL			0x4c
-#define   AZX_CORBCTL_RUN	(1 << 1)   /* enable DMA */
-#define   AZX_CORBCTL_CMEIE	(1 << 0)   /* enable memory error irq */
-#define AZX_REG_CORBSTS			0x4d
-#define   AZX_CORBSTS_CMEI	(1 << 0)   /* memory error indication */
-#define AZX_REG_CORBSIZE		0x4e
-
-#define AZX_REG_RIRBLBASE		0x50
-#define AZX_REG_RIRBUBASE		0x54
-#define AZX_REG_RIRBWP			0x58
-#define   AZX_RIRBWP_RST	(1 << 15)  /* write pointer reset */
-#define AZX_REG_RINTCNT			0x5a
-#define AZX_REG_RIRBCTL			0x5c
-#define   AZX_RBCTL_IRQ_EN	(1 << 0)   /* enable IRQ */
-#define   AZX_RBCTL_DMA_EN	(1 << 1)   /* enable DMA */
-#define   AZX_RBCTL_OVERRUN_EN	(1 << 2)   /* enable overrun irq */
-#define AZX_REG_RIRBSTS			0x5d
-#define   AZX_RBSTS_IRQ		(1 << 0)   /* response irq */
-#define   AZX_RBSTS_OVERRUN	(1 << 2)   /* overrun irq */
-#define AZX_REG_RIRBSIZE		0x5e
-
-#define AZX_REG_IC			0x60
-#define AZX_REG_IR			0x64
-#define AZX_REG_IRS			0x68
-#define   AZX_IRS_VALID		(1<<1)
-#define   AZX_IRS_BUSY		(1<<0)
-
-#define AZX_REG_DPLBASE			0x70
-#define AZX_REG_DPUBASE			0x74
-#define   AZX_DPLBASE_ENABLE	0x1	/* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define AZX_REG_SD_CTL			0x00
-#define AZX_REG_SD_STS			0x03
-#define AZX_REG_SD_LPIB			0x04
-#define AZX_REG_SD_CBL			0x08
-#define AZX_REG_SD_LVI			0x0c
-#define AZX_REG_SD_FIFOW		0x0e
-#define AZX_REG_SD_FIFOSIZE		0x10
-#define AZX_REG_SD_FORMAT		0x12
-#define AZX_REG_SD_BDLPL		0x18
-#define AZX_REG_SD_BDLPU		0x1c
-
-/* PCI space */
-#define AZX_PCIREG_TCSEL		0x44
-
-/*
- * other constants
- */
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE		4096
-#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
-#define AZX_MAX_FRAG		32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE	0x01
-#define RIRB_INT_OVERRUN	0x04
-#define RIRB_INT_MASK		0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS		8
-#define AZX_DEFAULT_CODECS	4
-#define STATESTS_INT_MASK	((1 << AZX_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
-#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
-#define SD_CTL_STRIPE		(3 << 16)	/* stripe control */
-#define SD_CTL_TRAFFIC_PRIO	(1 << 18)	/* traffic priority */
-#define SD_CTL_DIR		(1 << 19)	/* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT	20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
-#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
-#define SD_INT_COMPLETE		0x04	/* completion interrupt */
-#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
-				 SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define AZX_INT_ALL_STREAM	0xff	   /* all stream interrupts */
-#define AZX_INT_CTRL_EN	0x40000000 /* controller interrupt enable bit */
-#define AZX_INT_GLOBAL_EN	0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define AZX_MAX_CORB_ENTRIES	256
-#define AZX_MAX_RIRB_ENTRIES	256
-
-/* driver quirks (capabilities) */
-/* bits 0-7 are used for indicating driver type */
-#define AZX_DCAPS_NO_TCSEL	(1 << 8)	/* No Intel TCSEL bit */
-#define AZX_DCAPS_NO_MSI	(1 << 9)	/* No MSI support */
-#define AZX_DCAPS_SNOOP_MASK	(3 << 10)	/* snoop type mask */
-#define AZX_DCAPS_SNOOP_OFF	(1 << 12)	/* snoop default off */
-#define AZX_DCAPS_RIRB_DELAY	(1 << 13)	/* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)	/* Put a delay before read */
-#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)	/* X-Fi workaround */
-#define AZX_DCAPS_POSFIX_LPIB	(1 << 16)	/* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA	(1 << 17)	/* Use VIACOMBO as default */
-#define AZX_DCAPS_NO_64BIT	(1 << 18)	/* No 64bit address */
-#define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
-#define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
-#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21)	/* no buffer size alignment */
-/* 22 unused */
-#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
-#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24)	/* Assign devices in reverse order */
-#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)	/* Take LPIB as delay */
-#define AZX_DCAPS_PM_RUNTIME	(1 << 26)	/* runtime PM support */
-#define AZX_DCAPS_I915_POWERWELL (1 << 27)	/* HSW i915 powerwell support */
-#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)	/* CORBRP clears itself after reset */
-#define AZX_DCAPS_NO_MSI64      (1 << 29)	/* Stick to 32-bit MSIs */
-#define AZX_DCAPS_SEPARATE_STREAM_TAG	(1 << 30) /* capture and playback use separate stream tag */
-
-enum {
-	AZX_SNOOP_TYPE_NONE ,
-	AZX_SNOOP_TYPE_SCH,
-	AZX_SNOOP_TYPE_ATI,
-	AZX_SNOOP_TYPE_NVIDIA,
-};
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
-
-struct azx_dev {
-	struct snd_dma_buffer bdl; /* BDL buffer */
-	u32 *posbuf;		/* position buffer pointer */
-
-	unsigned int bufsize;	/* size of the play buffer in bytes */
-	unsigned int period_bytes; /* size of the period in bytes */
-	unsigned int frags;	/* number for period in the play buffer */
-	unsigned int fifo_size;	/* FIFO size */
-	unsigned long start_wallclk;	/* start + minimum wallclk */
-	unsigned long period_wallclk;	/* wallclk for period */
-
-	void __iomem *sd_addr;	/* stream descriptor pointer */
-
-	u32 sd_int_sta_mask;	/* stream int status mask */
-
-	/* pcm support */
-	struct snd_pcm_substream *substream;	/* assigned substream,
-						 * set in PCM open
-						 */
-	unsigned int format_val;	/* format value to be set in the
-					 * controller and the codec
-					 */
-	unsigned char stream_tag;	/* assigned stream */
-	unsigned char index;		/* stream index */
-	int assigned_key;		/* last device# key assigned to */
-
-	unsigned int opened:1;
-	unsigned int running:1;
-	unsigned int irq_pending:1;
-	unsigned int prepared:1;
-	unsigned int locked:1;
-	/*
-	 * For VIA:
-	 *  A flag to ensure DMA position is 0
-	 *  when link position is not greater than FIFO size
-	 */
-	unsigned int insufficient:1;
-	unsigned int wc_marked:1;
-	unsigned int no_period_wakeup:1;
-
-	struct timecounter  azx_tc;
-	struct cyclecounter azx_cc;
-
-	int delay_negative_threshold;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-	/* Allows dsp load to have sole access to the playback stream. */
-	struct mutex dsp_mutex;
-#endif
-};
-
-/* CORB/RIRB */
-struct azx_rb {
-	u32 *buf;		/* CORB/RIRB buffer
-				 * Each CORB entry is 4byte, RIRB is 8byte
-				 */
-	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
-	/* for RIRB */
-	unsigned short rp, wp;	/* read/write pointers */
-	int cmds[AZX_MAX_CODECS];	/* number of pending requests */
-	u32 res[AZX_MAX_CODECS];	/* last read value */
-};
-
-struct azx;
-
-/* Functions to read/write to hda registers. */
-struct hda_controller_ops {
-	/* Register Access */
-	void (*reg_writel)(u32 value, u32 __iomem *addr);
-	u32 (*reg_readl)(u32 __iomem *addr);
-	void (*reg_writew)(u16 value, u16 __iomem *addr);
-	u16 (*reg_readw)(u16 __iomem *addr);
-	void (*reg_writeb)(u8 value, u8 __iomem *addr);
-	u8 (*reg_readb)(u8 __iomem *addr);
-	/* Disable msi if supported, PCI only */
-	int (*disable_msi_reset_irq)(struct azx *);
-	/* Allocation ops */
-	int (*dma_alloc_pages)(struct azx *chip,
-			       int type,
-			       size_t size,
-			       struct snd_dma_buffer *buf);
-	void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf);
-	int (*substream_alloc_pages)(struct azx *chip,
-				     struct snd_pcm_substream *substream,
-				     size_t size);
-	int (*substream_free_pages)(struct azx *chip,
-				    struct snd_pcm_substream *substream);
-	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
-				 struct vm_area_struct *area);
-	/* Check if current position is acceptable */
-	int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
-};
-
-struct azx_pcm {
-	struct azx *chip;
-	struct snd_pcm *pcm;
-	struct hda_codec *codec;
-	struct hda_pcm_stream *hinfo[2];
-	struct list_head list;
-};
-
-typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *);
-typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos);
-
-struct azx {
-	struct snd_card *card;
-	struct pci_dev *pci;
-	int dev_index;
-
-	/* chip type specific */
-	int driver_type;
-	unsigned int driver_caps;
-	int playback_streams;
-	int playback_index_offset;
-	int capture_streams;
-	int capture_index_offset;
-	int num_streams;
-	const int *jackpoll_ms; /* per-card jack poll interval */
-
-	/* Register interaction. */
-	const struct hda_controller_ops *ops;
-
-	/* position adjustment callbacks */
-	azx_get_pos_callback_t get_position[2];
-	azx_get_delay_callback_t get_delay[2];
-
-	/* pci resources */
-	unsigned long addr;
-	void __iomem *remap_addr;
-	int irq;
-
-	/* locks */
-	spinlock_t reg_lock;
-	struct mutex open_mutex; /* Prevents concurrent open/close operations */
-
-	/* streams (x num_streams) */
-	struct azx_dev *azx_dev;
-
-	/* PCM */
-	struct list_head pcm_list; /* azx_pcm list */
-
-	/* HD codec */
-	unsigned short codec_mask;
-	int  codec_probe_mask; /* copied from probe_mask option */
-	struct hda_bus *bus;
-	unsigned int beep_mode;
-
-	/* CORB/RIRB */
-	struct azx_rb corb;
-	struct azx_rb rirb;
-
-	/* CORB/RIRB and position buffers */
-	struct snd_dma_buffer rb;
-	struct snd_dma_buffer posbuf;
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
-	const struct firmware *fw;
-#endif
-
-	/* flags */
-	const int *bdl_pos_adj;
-	int poll_count;
-	unsigned int running:1;
-	unsigned int initialized:1;
-	unsigned int single_cmd:1;
-	unsigned int polling_mode:1;
-	unsigned int msi:1;
-	unsigned int probing:1; /* codec probing phase */
-	unsigned int snoop:1;
-	unsigned int align_buffer_size:1;
-	unsigned int region_requested:1;
-	unsigned int disabled:1; /* disabled by VGA-switcher */
-
-	/* for debugging */
-	unsigned int last_cmd[AZX_MAX_CODECS];
-
-	/* reboot notifier (for mysterious hangup problem at power-down) */
-	struct notifier_block reboot_notifier;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-	struct azx_dev saved_azx_dev;
-#endif
-};
-
-#ifdef CONFIG_X86
-#define azx_snoop(chip)		((chip)->snoop)
-#else
-#define azx_snoop(chip)		true
-#endif
-
-/*
- * macros for easy use
- */
-
-#define azx_writel(chip, reg, value) \
-	((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readl(chip, reg) \
-	((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg))
-#define azx_writew(chip, reg, value) \
-	((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readw(chip, reg) \
-	((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg))
-#define azx_writeb(chip, reg, value) \
-	((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readb(chip, reg) \
-	((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg))
-
-#define azx_sd_writel(chip, dev, reg, value) \
-	((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readl(chip, dev, reg) \
-	((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_writew(chip, dev, reg, value) \
-	((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readw(chip, dev, reg) \
-	((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_writeb(chip, dev, reg, value) \
-	((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readb(chip, dev, reg) \
-	((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg))
-
-#endif /* __SOUND_HDA_PRIV_H */
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 05e19f7..ee62307 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -32,6 +32,10 @@
 module_param(dump_coef, int, 0644);
 MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)");
 
+/* always use noncached version */
+#define param_read(codec, nid, parm) \
+	snd_hdac_read_parm_uncached(&(codec)->core, nid, parm)
+
 static char *bits_names(unsigned int bits, char *names[], int size)
 {
 	int i, n;
@@ -99,10 +103,10 @@
 static void print_nid_pcms(struct snd_info_buffer *buffer,
 			   struct hda_codec *codec, hda_nid_t nid)
 {
-	int pcm, type;
+	int type;
 	struct hda_pcm *cpcm;
-	for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-		cpcm = &codec->pcm_info[pcm];
+
+	list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
 		for (type = 0; type < 2; type++) {
 			if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
 				continue;
@@ -119,9 +123,8 @@
 			   struct hda_codec *codec, hda_nid_t nid, int dir)
 {
 	unsigned int caps;
-	caps = snd_hda_param_read(codec, nid,
-				  dir == HDA_OUTPUT ?
-				    AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+	caps = param_read(codec, nid, dir == HDA_OUTPUT ?
+			  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
 	if (caps == -1 || caps == 0) {
 		snd_iprintf(buffer, "N/A\n");
 		return;
@@ -225,8 +228,8 @@
 static void print_pcm_caps(struct snd_info_buffer *buffer,
 			   struct hda_codec *codec, hda_nid_t nid)
 {
-	unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-	unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	unsigned int pcm = param_read(codec, nid, AC_PAR_PCM);
+	unsigned int stream = param_read(codec, nid, AC_PAR_STREAM);
 	if (pcm == -1 || stream == -1) {
 		snd_iprintf(buffer, "N/A\n");
 		return;
@@ -273,7 +276,7 @@
 	static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
 	unsigned int caps, val;
 
-	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+	caps = param_read(codec, nid, AC_PAR_PIN_CAP);
 	snd_iprintf(buffer, "  Pincap 0x%08x:", caps);
 	if (caps & AC_PINCAP_IN)
 		snd_iprintf(buffer, " IN");
@@ -289,7 +292,7 @@
 		snd_iprintf(buffer, " Balanced");
 	if (caps & AC_PINCAP_HDMI) {
 		/* Realtek uses this bit as a different meaning */
-		if ((codec->vendor_id >> 16) == 0x10ec)
+		if ((codec->core.vendor_id >> 16) == 0x10ec)
 			snd_iprintf(buffer, " R/L");
 		else {
 			if (caps & AC_PINCAP_HBR)
@@ -401,8 +404,7 @@
 static void print_vol_knob(struct snd_info_buffer *buffer,
 			   struct hda_codec *codec, hda_nid_t nid)
 {
-	unsigned int cap = snd_hda_param_read(codec, nid,
-					      AC_PAR_VOL_KNB_CAP);
+	unsigned int cap = param_read(codec, nid, AC_PAR_VOL_KNB_CAP);
 	snd_iprintf(buffer, "  Volume-Knob: delta=%d, steps=%d, ",
 		    (cap >> 7) & 1, cap & 0x7f);
 	cap = snd_hda_codec_read(codec, nid, 0,
@@ -487,7 +489,7 @@
 		[ilog2(AC_PWRST_EPSS)]		= "EPSS",
 	};
 
-	int sup = snd_hda_param_read(codec, nid, AC_PAR_POWER_STATE);
+	int sup = param_read(codec, nid, AC_PAR_POWER_STATE);
 	int pwr = snd_hda_codec_read(codec, nid, 0,
 				     AC_VERB_GET_POWER_STATE, 0);
 	if (sup != -1)
@@ -531,8 +533,7 @@
 			    struct hda_codec *codec, hda_nid_t nid)
 {
 	unsigned int i, ncoeff, oldindex;
-	unsigned int proc_caps = snd_hda_param_read(codec, nid,
-						    AC_PAR_PROC_CAP);
+	unsigned int proc_caps = param_read(codec, nid, AC_PAR_PROC_CAP);
 	ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT;
 	snd_iprintf(buffer, "  Processing caps: benign=%d, ncoeff=%d\n",
 		    proc_caps & AC_PCAP_BENIGN, ncoeff);
@@ -597,7 +598,7 @@
 		       struct hda_codec *codec, hda_nid_t nid)
 {
 	unsigned int gpio =
-		snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+		param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
 	unsigned int enable, direction, wake, unsol, sticky, data;
 	int i, max;
 	snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
@@ -667,13 +668,9 @@
 	}
 }
 
-static void print_codec_info(struct snd_info_entry *entry,
-			     struct snd_info_buffer *buffer)
+static void print_codec_core_info(struct hdac_device *codec,
+				  struct snd_info_buffer *buffer)
 {
-	struct hda_codec *codec = entry->private_data;
-	hda_nid_t nid;
-	int i, nodes;
-
 	snd_iprintf(buffer, "Codec: ");
 	if (codec->vendor_name && codec->chip_name)
 		snd_iprintf(buffer, "%s %s\n",
@@ -695,34 +692,43 @@
 		snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
 	else
 		snd_iprintf(buffer, "No Modem Function Group found\n");
+}
 
-	if (! codec->afg)
+static void print_codec_info(struct snd_info_entry *entry,
+			     struct snd_info_buffer *buffer)
+{
+	struct hda_codec *codec = entry->private_data;
+	hda_nid_t nid, fg;
+	int i, nodes;
+
+	print_codec_core_info(&codec->core, buffer);
+	fg = codec->core.afg;
+	if (!fg)
 		return;
 	snd_hda_power_up(codec);
 	snd_iprintf(buffer, "Default PCM:\n");
-	print_pcm_caps(buffer, codec, codec->afg);
+	print_pcm_caps(buffer, codec, fg);
 	snd_iprintf(buffer, "Default Amp-In caps: ");
-	print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
+	print_amp_caps(buffer, codec, fg, HDA_INPUT);
 	snd_iprintf(buffer, "Default Amp-Out caps: ");
-	print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
-	snd_iprintf(buffer, "State of AFG node 0x%02x:\n", codec->afg);
-	print_power_state(buffer, codec, codec->afg);
+	print_amp_caps(buffer, codec, fg, HDA_OUTPUT);
+	snd_iprintf(buffer, "State of AFG node 0x%02x:\n", fg);
+	print_power_state(buffer, codec, fg);
 
-	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+	nodes = snd_hda_get_sub_nodes(codec, fg, &nid);
 	if (! nid || nodes < 0) {
 		snd_iprintf(buffer, "Invalid AFG subtree\n");
 		snd_hda_power_down(codec);
 		return;
 	}
 
-	print_gpio(buffer, codec, codec->afg);
+	print_gpio(buffer, codec, fg);
 	if (codec->proc_widget_hook)
-		codec->proc_widget_hook(buffer, codec, codec->afg);
+		codec->proc_widget_hook(buffer, codec, fg);
 
 	for (i = 0; i < nodes; i++, nid++) {
 		unsigned int wid_caps =
-			snd_hda_param_read(codec, nid,
-					   AC_PAR_AUDIO_WIDGET_CAP);
+			param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
 		unsigned int wid_type = get_wcaps_type(wid_caps);
 		hda_nid_t *conn = NULL;
 		int conn_len = 0;
@@ -860,8 +866,8 @@
 	struct snd_info_entry *entry;
 	int err;
 
-	snprintf(name, sizeof(name), "codec#%d", codec->addr);
-	err = snd_card_proc_new(codec->bus->card, name, &entry);
+	snprintf(name, sizeof(name), "codec#%d", codec->core.addr);
+	err = snd_card_proc_new(codec->card, name, &entry);
 	if (err < 0)
 		return err;
 
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
index ccc962a..a6e3d9b 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/pci/hda/hda_sysfs.c
@@ -48,33 +48,33 @@
 static DEVICE_ATTR_RO(power_off_acct);
 #endif /* CONFIG_PM */
 
-#define CODEC_INFO_SHOW(type)					\
+#define CODEC_INFO_SHOW(type, field)				\
 static ssize_t type##_show(struct device *dev,			\
 			   struct device_attribute *attr,	\
 			   char *buf)				\
 {								\
 	struct hda_codec *codec = dev_get_drvdata(dev);		\
-	return sprintf(buf, "0x%x\n", codec->type);		\
+	return sprintf(buf, "0x%x\n", codec->field);		\
 }
 
-#define CODEC_INFO_STR_SHOW(type)				\
+#define CODEC_INFO_STR_SHOW(type, field)			\
 static ssize_t type##_show(struct device *dev,			\
 			     struct device_attribute *attr,	\
 					char *buf)		\
 {								\
 	struct hda_codec *codec = dev_get_drvdata(dev);		\
 	return sprintf(buf, "%s\n",				\
-		       codec->type ? codec->type : "");		\
+		       codec->field ? codec->field : "");	\
 }
 
-CODEC_INFO_SHOW(vendor_id);
-CODEC_INFO_SHOW(subsystem_id);
-CODEC_INFO_SHOW(revision_id);
-CODEC_INFO_SHOW(afg);
-CODEC_INFO_SHOW(mfg);
-CODEC_INFO_STR_SHOW(vendor_name);
-CODEC_INFO_STR_SHOW(chip_name);
-CODEC_INFO_STR_SHOW(modelname);
+CODEC_INFO_SHOW(vendor_id, core.vendor_id);
+CODEC_INFO_SHOW(subsystem_id, core.subsystem_id);
+CODEC_INFO_SHOW(revision_id, core.revision_id);
+CODEC_INFO_SHOW(afg, core.afg);
+CODEC_INFO_SHOW(mfg, core.mfg);
+CODEC_INFO_STR_SHOW(vendor_name, core.vendor_name);
+CODEC_INFO_STR_SHOW(chip_name, core.chip_name);
+CODEC_INFO_STR_SHOW(modelname, modelname);
 
 static ssize_t pin_configs_show(struct hda_codec *codec,
 				struct snd_array *list,
@@ -149,7 +149,7 @@
 	err = snd_hda_codec_build_controls(codec);
 	if (err < 0)
 		goto error;
-	err = snd_card_register(codec->bus->card);
+	err = snd_card_register(codec->card);
  error:
 	snd_hda_power_down(codec);
 	return err;
@@ -170,7 +170,7 @@
 	return s;
 }
 
-#define CODEC_INFO_STORE(type)					\
+#define CODEC_INFO_STORE(type, field)				\
 static ssize_t type##_store(struct device *dev,			\
 			    struct device_attribute *attr,	\
 			    const char *buf, size_t count)	\
@@ -180,11 +180,11 @@
 	int err = kstrtoul(buf, 0, &val);			\
 	if (err < 0)						\
 		return err;					\
-	codec->type = val;					\
+	codec->field = val;					\
 	return count;						\
 }
 
-#define CODEC_INFO_STR_STORE(type)				\
+#define CODEC_INFO_STR_STORE(type, field)			\
 static ssize_t type##_store(struct device *dev,			\
 			    struct device_attribute *attr,	\
 			    const char *buf, size_t count)	\
@@ -193,17 +193,17 @@
 	char *s = kstrndup_noeol(buf, 64);			\
 	if (!s)							\
 		return -ENOMEM;					\
-	kfree(codec->type);					\
-	codec->type = s;					\
+	kfree(codec->field);					\
+	codec->field = s;					\
 	return count;						\
 }
 
-CODEC_INFO_STORE(vendor_id);
-CODEC_INFO_STORE(subsystem_id);
-CODEC_INFO_STORE(revision_id);
-CODEC_INFO_STR_STORE(vendor_name);
-CODEC_INFO_STR_STORE(chip_name);
-CODEC_INFO_STR_STORE(modelname);
+CODEC_INFO_STORE(vendor_id, core.vendor_id);
+CODEC_INFO_STORE(subsystem_id, core.subsystem_id);
+CODEC_INFO_STORE(revision_id, core.revision_id);
+CODEC_INFO_STR_STORE(vendor_name, core.vendor_name);
+CODEC_INFO_STR_STORE(chip_name, core.chip_name);
+CODEC_INFO_STR_STORE(modelname, modelname);
 
 #define CODEC_ACTION_STORE(type)				\
 static ssize_t type##_store(struct device *dev,			\
@@ -552,10 +552,10 @@
 
 	*codecp = NULL;
 	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
-		list_for_each_entry(codec, &bus->codec_list, list) {
-			if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
-			    (subid <= 0 || codec->subsystem_id == subid) &&
-			    codec->addr == caddr) {
+		list_for_each_codec(codec, bus) {
+			if ((vendorid <= 0 || codec->core.vendor_id == vendorid) &&
+			    (subid <= 0 || codec->core.subsystem_id == subid) &&
+			    codec->core.addr == caddr) {
 				*codecp = codec;
 				break;
 			}
@@ -595,8 +595,8 @@
 static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
 				 struct hda_codec **codecp)
 {
-	kfree((*codecp)->chip_name);
-	(*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
+	kfree((*codecp)->core.chip_name);
+	(*codecp)->core.chip_name = kstrdup(buf, GFP_KERNEL);
 }
 
 #define DEFINE_PARSE_ID_MODE(name) \
@@ -605,7 +605,7 @@
 { \
 	unsigned long val; \
 	if (!kstrtoul(buf, 0, &val)) \
-		(*codecp)->name = val; \
+		(*codecp)->core.name = val; \
 }
 
 DEFINE_PARSE_ID_MODE(vendor_id);
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 375e94f..2e4fd5c 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -37,7 +37,6 @@
 
 #include "hda_codec.h"
 #include "hda_controller.h"
-#include "hda_priv.h"
 
 /* Defines for Nvidia Tegra HDA support */
 #define HDA_BAR0           0x8000
@@ -82,7 +81,7 @@
 MODULE_PARM_DESC(power_save,
 		 "Automatic power-saving timeout (in seconds, 0 = disable).");
 #else
-static int power_save = 0;
+#define power_save	0
 #endif
 
 /*
@@ -250,14 +249,9 @@
 {
 	struct snd_card *card = dev_get_drvdata(dev);
 	struct azx *chip = card->private_data;
-	struct azx_pcm *p;
 	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	list_for_each_entry(p, &chip->pcm_list, list)
-		snd_pcm_suspend_all(p->pcm);
-	if (chip->initialized)
-		snd_hda_suspend(chip->bus);
 
 	azx_stop_chip(chip);
 	azx_enter_link_reset(chip);
@@ -278,7 +272,6 @@
 
 	azx_init_chip(chip, 1);
 
-	snd_hda_resume(chip->bus);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
 	return 0;
@@ -297,8 +290,6 @@
 	int i;
 	struct azx *chip = device->device_data;
 
-	azx_notifier_unregister(chip);
-
 	if (chip->initialized) {
 		for (i = 0; i < chip->num_streams; i++)
 			azx_stream_stop(chip, &chip->azx_dev[i]);
@@ -344,17 +335,6 @@
 	return 0;
 }
 
-/*
- * The codecs were powered up in snd_hda_codec_new().
- * Now all initialization done, so turn them down if possible
- */
-static void power_down_all_codecs(struct azx *chip)
-{
-	struct hda_codec *codec;
-	list_for_each_entry(codec, &chip->bus->codec_list, list)
-		snd_hda_power_down(codec);
-}
-
 static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
 {
 	struct snd_card *card = chip->card;
@@ -503,7 +483,11 @@
 		goto out_free;
 
 	/* create codec instances */
-	err = azx_codec_create(chip, NULL, 0, &power_save);
+	err = azx_bus_create(chip, NULL);
+	if (err < 0)
+		goto out_free;
+
+	err = azx_probe_codecs(chip, 0);
 	if (err < 0)
 		goto out_free;
 
@@ -511,23 +495,12 @@
 	if (err < 0)
 		goto out_free;
 
-	/* create PCM streams */
-	err = snd_hda_build_pcms(chip->bus);
-	if (err < 0)
-		goto out_free;
-
-	/* create mixer controls */
-	err = azx_mixer_create(chip);
-	if (err < 0)
-		goto out_free;
-
 	err = snd_card_register(chip->card);
 	if (err < 0)
 		goto out_free;
 
 	chip->running = 1;
-	power_down_all_codecs(chip);
-	azx_notifier_register(chip);
+	snd_hda_set_power_save(chip->bus, power_save * 1000);
 
 	return 0;
 
@@ -541,6 +514,18 @@
 	return snd_card_free(dev_get_drvdata(&pdev->dev));
 }
 
+static void hda_tegra_shutdown(struct platform_device *pdev)
+{
+	struct snd_card *card = dev_get_drvdata(&pdev->dev);
+	struct azx *chip;
+
+	if (!card)
+		return;
+	chip = card->private_data;
+	if (chip && chip->running)
+		azx_stop_chip(chip);
+}
+
 static struct platform_driver tegra_platform_hda = {
 	.driver = {
 		.name = "tegra-hda",
@@ -549,6 +534,7 @@
 	},
 	.probe = hda_tegra_probe,
 	.remove = hda_tegra_remove,
+	.shutdown = hda_tegra_shutdown,
 };
 module_platform_driver(tegra_platform_hda);
 
diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h
deleted file mode 100644
index 3a1c631..0000000
--- a/sound/pci/hda/hda_trace.h
+++ /dev/null
@@ -1,143 +0,0 @@
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hda
-#define TRACE_INCLUDE_FILE hda_trace
-
-#if !defined(_TRACE_HDA_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_HDA_H
-
-#include <linux/tracepoint.h>
-
-struct hda_bus;
-struct hda_codec;
-
-DECLARE_EVENT_CLASS(hda_cmd,
-
-	TP_PROTO(struct hda_codec *codec, unsigned int val),
-
-	TP_ARGS(codec, val),
-
-	TP_STRUCT__entry(
-		__field( unsigned int, card )
-		__field( unsigned int, addr )
-		__field( unsigned int, val )
-	),
-
-	TP_fast_assign(
-		__entry->card = (codec)->bus->card->number;
-		__entry->addr = (codec)->addr;
-		__entry->val = (val);
-	),
-
-	TP_printk("[%d:%d] val=%x", __entry->card, __entry->addr, __entry->val)
-);
-
-DEFINE_EVENT(hda_cmd, hda_send_cmd,
-	TP_PROTO(struct hda_codec *codec, unsigned int val),
-	TP_ARGS(codec, val)
-);
-
-DEFINE_EVENT(hda_cmd, hda_get_response,
-	TP_PROTO(struct hda_codec *codec, unsigned int val),
-	TP_ARGS(codec, val)
-);
-
-TRACE_EVENT(hda_bus_reset,
-
-	TP_PROTO(struct hda_bus *bus),
-
-	TP_ARGS(bus),
-
-	TP_STRUCT__entry(
-		__field( unsigned int, card )
-	),
-
-	TP_fast_assign(
-		__entry->card = (bus)->card->number;
-	),
-
-	TP_printk("[%d]", __entry->card)
-);
-
-#ifdef CONFIG_PM
-DECLARE_EVENT_CLASS(hda_power,
-
-	TP_PROTO(struct hda_codec *codec),
-
-	TP_ARGS(codec),
-
-	TP_STRUCT__entry(
-		__field( unsigned int, card )
-		__field( unsigned int, addr )
-	),
-
-	TP_fast_assign(
-		__entry->card = (codec)->bus->card->number;
-		__entry->addr = (codec)->addr;
-	),
-
-	TP_printk("[%d:%d]", __entry->card, __entry->addr)
-);
-
-DEFINE_EVENT(hda_power, hda_power_down,
-	TP_PROTO(struct hda_codec *codec),
-	TP_ARGS(codec)
-);
-
-DEFINE_EVENT(hda_power, hda_power_up,
-	TP_PROTO(struct hda_codec *codec),
-	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),
-
-	TP_ARGS(bus, res, res_ex),
-
-	TP_STRUCT__entry(
-		__field( unsigned int, card )
-		__field( u32, res )
-		__field( u32, res_ex )
-	),
-
-	TP_fast_assign(
-		__entry->card = (bus)->card->number;
-		__entry->res = res;
-		__entry->res_ex = res_ex;
-	),
-
-	TP_printk("[%d] res=%x, res_ex=%x", __entry->card,
-		  __entry->res, __entry->res_ex)
-);
-
-#endif /* _TRACE_HDA_H */
-
-/* This part must be outside protection */
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#include <trace/define_trace.h>
diff --git a/sound/pci/hda/local.h b/sound/pci/hda/local.h
new file mode 100644
index 0000000..28cb7f9
--- /dev/null
+++ b/sound/pci/hda/local.h
@@ -0,0 +1,39 @@
+/*
+ */
+
+#ifndef __HDAC_LOCAL_H
+#define __HDAC_LOCAL_H
+
+int hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm);
+
+#define get_wcaps(codec, nid) \
+	hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
+/* get the widget type from widget capability bits */
+static inline int get_wcaps_type(unsigned int wcaps)
+{
+	if (!wcaps)
+		return -1; /* invalid type */
+	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+}
+
+#define get_pin_caps(codec, nid) \
+	hdac_read_parm(codec, nid, AC_PAR_PIN_CAP)
+
+static inline
+unsigned int get_pin_cfg(struct hdac_device *codec, hda_nid_t nid)
+{
+	unsigned int val;
+
+	if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
+		return -1;
+	return val;
+}
+
+#define get_amp_caps(codec, nid, dir) \
+	hdac_read_parm(codec, nid, (dir) == HDA_OUTPUT ? \
+		       AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP)
+
+#define get_power_caps(codec, nid) \
+	hdac_read_parm(codec, nid, AC_PAR_POWER_STATE)
+
+#endif /* __HDAC_LOCAL_H */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index d285904..231f890 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -99,7 +99,7 @@
 static void ad198x_power_eapd(struct hda_codec *codec)
 {
 	/* We currently only handle front, HP */
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x11d41882:
 	case 0x11d4882a:
 	case 0x11d41884:
@@ -777,7 +777,6 @@
 		return 0;
 
 	mutex_lock(&codec->control_mutex);
-	codec->cached_write = 1;
 	path = snd_hda_get_path_from_idx(codec,
 					 spec->smux_paths[spec->cur_smux]);
 	if (path)
@@ -786,9 +785,7 @@
 	if (path)
 		snd_hda_activate_path(codec, path, true, true);
 	spec->cur_smux = val;
-	codec->cached_write = 0;
 	mutex_unlock(&codec->control_mutex);
-	snd_hda_codec_flush_cache(codec); /* flush the updates */
 	return 1;
 }
 
@@ -1004,18 +1001,17 @@
 				 const struct hda_fixup *fix, int action)
 {
 	struct ad198x_spec *spec = codec->spec;
-	static const struct hda_verb gpio_init_verbs[] = {
-		{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-		{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-		{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
-		{},
-	};
 
 	switch (action) {
 	case HDA_FIXUP_ACT_PRE_PROBE:
 		spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
 		spec->gen.own_eapd_ctl = 1;
-		snd_hda_sequence_write_cache(codec, gpio_init_verbs);
+		snd_hda_codec_write_cache(codec, 0x01, 0,
+					  AC_VERB_SET_GPIO_MASK, 0x02);
+		snd_hda_codec_write_cache(codec, 0x01, 0,
+					  AC_VERB_SET_GPIO_DIRECTION, 0x02);
+		snd_hda_codec_write_cache(codec, 0x01, 0,
+					  AC_VERB_SET_GPIO_DATA, 0x02);
 		break;
 	case HDA_FIXUP_ACT_PROBE:
 		if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
@@ -1194,20 +1190,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
 
-static struct hda_codec_preset_list analog_list = {
+static struct hda_codec_driver analog_driver = {
 	.preset = snd_hda_preset_analog,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_analog_init(void)
-{
-	return snd_hda_add_codec_preset(&analog_list);
-}
-
-static void __exit patch_analog_exit(void)
-{
-	snd_hda_delete_codec_preset(&analog_list);
-}
-
-module_init(patch_analog_init)
-module_exit(patch_analog_exit)
+module_hda_codec_driver(analog_driver);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 5e65999..4473026 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -98,20 +98,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
 
-static struct hda_codec_preset_list ca0110_list = {
+static struct hda_codec_driver ca0110_driver = {
 	.preset = snd_hda_preset_ca0110,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_ca0110_init(void)
-{
-	return snd_hda_add_codec_preset(&ca0110_list);
-}
-
-static void __exit patch_ca0110_exit(void)
-{
-	snd_hda_delete_codec_preset(&ca0110_list);
-}
-
-module_init(patch_ca0110_init)
-module_exit(patch_ca0110_exit)
+module_hda_codec_driver(ca0110_driver);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index e0383ee..4a4e7b2 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -719,7 +719,6 @@
 	unsigned int num_inputs;
 	hda_nid_t shared_mic_nid;
 	hda_nid_t shared_out_nid;
-	struct hda_pcm pcm_rec[5]; /* PCM information */
 
 	/* chip access */
 	struct mutex chipio_mutex; /* chip access mutex */
@@ -3132,7 +3131,7 @@
 
 	codec_dbg(codec, "ca0132_select_out\n");
 
-	snd_hda_power_up(codec);
+	snd_hda_power_up_pm(codec);
 
 	auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
 
@@ -3216,7 +3215,7 @@
 	}
 
 exit:
-	snd_hda_power_down(codec);
+	snd_hda_power_down_pm(codec);
 
 	return err < 0 ? err : 0;
 }
@@ -3294,7 +3293,7 @@
 
 	codec_dbg(codec, "ca0132_select_mic\n");
 
-	snd_hda_power_up(codec);
+	snd_hda_power_up_pm(codec);
 
 	auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
 
@@ -3327,7 +3326,7 @@
 		ca0132_effects_set(codec, VOICE_FOCUS, 0);
 	}
 
-	snd_hda_power_down(codec);
+	snd_hda_power_down_pm(codec);
 
 	return 0;
 }
@@ -4036,12 +4035,11 @@
 static int ca0132_build_pcms(struct hda_codec *codec)
 {
 	struct ca0132_spec *spec = codec->spec;
-	struct hda_pcm *info = spec->pcm_rec;
+	struct hda_pcm *info;
 
-	codec->pcm_info = info;
-	codec->num_pcms = 0;
-
-	info->name = "CA0132 Analog";
+	info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
+	if (!info)
+		return -ENOMEM;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
@@ -4049,27 +4047,27 @@
 	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
-	codec->num_pcms++;
 
-	info++;
-	info->name = "CA0132 Analog Mic-In2";
+	info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
+	if (!info)
+		return -ENOMEM;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
-	codec->num_pcms++;
 
-	info++;
-	info->name = "CA0132 What U Hear";
+	info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear");
+	if (!info)
+		return -ENOMEM;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
-	codec->num_pcms++;
 
 	if (!spec->dig_out && !spec->dig_in)
 		return 0;
 
-	info++;
-	info->name = "CA0132 Digital";
+	info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+	if (!info)
+		return -ENOMEM;
 	info->pcm_type = HDA_PCM_TYPE_SPDIF;
 	if (spec->dig_out) {
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
@@ -4081,7 +4079,6 @@
 			ca0132_pcm_digital_capture;
 		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
 	}
-	codec->num_pcms++;
 
 	return 0;
 }
@@ -4246,13 +4243,9 @@
 {
 	struct ca0132_spec *spec = codec->spec;
 	int i;
-	hda_nid_t nid;
 
 	codec_dbg(codec, "ca0132_refresh_widget_caps.\n");
-	nid = codec->start_nid;
-	for (i = 0; i < codec->num_nodes; i++, nid++)
-		codec->wcaps[i] = snd_hda_param_read(codec, nid,
-						     AC_PAR_AUDIO_WIDGET_CAP);
+	snd_hda_codec_update_widgets(codec);
 
 	for (i = 0; i < spec->multiout.num_dacs; i++)
 		refresh_amp_caps(codec, spec->dacs[i], HDA_OUTPUT);
@@ -4352,7 +4345,7 @@
 	const struct dsp_image_seg *dsp_os_image;
 	const struct firmware *fw_entry;
 
-	if (request_firmware(&fw_entry, EFX_FILE, codec->bus->card->dev) != 0)
+	if (request_firmware(&fw_entry, EFX_FILE, codec->card->dev) != 0)
 		return false;
 
 	dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
@@ -4413,8 +4406,7 @@
 	 * state machine run.
 	 */
 	cancel_delayed_work_sync(&spec->unsol_hp_work);
-	queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work,
-			   msecs_to_jiffies(500));
+	schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
 	cb->tbl->block_report = 1;
 }
 
@@ -4554,7 +4546,7 @@
 		spec->dsp_state = DSP_DOWNLOAD_INIT;
 	spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
 
-	snd_hda_power_up(codec);
+	snd_hda_power_up_pm(codec);
 
 	ca0132_init_unsol(codec);
 
@@ -4585,7 +4577,7 @@
 
 	snd_hda_jack_report_sync(codec);
 
-	snd_hda_power_down(codec);
+	snd_hda_power_down_pm(codec);
 
 	return 0;
 }
@@ -4702,20 +4694,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative Sound Core3D codec");
 
-static struct hda_codec_preset_list ca0132_list = {
+static struct hda_codec_driver ca0132_driver = {
 	.preset = snd_hda_preset_ca0132,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_ca0132_init(void)
-{
-	return snd_hda_add_codec_preset(&ca0132_list);
-}
-
-static void __exit patch_ca0132_exit(void)
-{
-	snd_hda_delete_codec_preset(&ca0132_list);
-}
-
-module_init(patch_ca0132_init)
-module_exit(patch_ca0132_exit)
+module_hda_codec_driver(ca0132_driver);
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index dd2b3d9..50e9dd6 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1221,20 +1221,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
 
-static struct hda_codec_preset_list cirrus_list = {
+static struct hda_codec_driver cirrus_driver = {
 	.preset = snd_hda_preset_cirrus,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_cirrus_init(void)
-{
-	return snd_hda_add_codec_preset(&cirrus_list);
-}
-
-static void __exit patch_cirrus_exit(void)
-{
-	snd_hda_delete_codec_preset(&cirrus_list);
-}
-
-module_init(patch_cirrus_init)
-module_exit(patch_cirrus_exit)
+module_hda_codec_driver(cirrus_driver);
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index c895a8f..617d901 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -137,20 +137,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("C-Media HD-audio codec");
 
-static struct hda_codec_preset_list cmedia_list = {
+static struct hda_codec_driver cmedia_driver = {
 	.preset = snd_hda_preset_cmedia,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_cmedia_init(void)
-{
-	return snd_hda_add_codec_preset(&cmedia_list);
-}
-
-static void __exit patch_cmedia_exit(void)
-{
-	snd_hda_delete_codec_preset(&cmedia_list);
-}
-
-module_init(patch_cmedia_init)
-module_exit(patch_cmedia_exit)
+module_hda_codec_driver(cmedia_driver);
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index da67ea8..f8f0dfb 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -103,10 +103,9 @@
 static void cx_auto_parse_beep(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	hda_nid_t nid, end_nid;
+	hda_nid_t nid;
 
-	end_nid = codec->start_nid + codec->num_nodes;
-	for (nid = codec->start_nid; nid < end_nid; nid++)
+	for_each_hda_codec_node(nid, codec)
 		if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
 			set_beep_amp(spec, nid, 0, HDA_OUTPUT);
 			break;
@@ -120,10 +119,9 @@
 static void cx_auto_parse_eapd(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	hda_nid_t nid, end_nid;
+	hda_nid_t nid;
 
-	end_nid = codec->start_nid + codec->num_nodes;
-	for (nid = codec->start_nid; nid < end_nid; nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
 			continue;
 		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
@@ -304,6 +302,7 @@
 	switch (action) {
 	case HDA_FIXUP_ACT_PRE_PROBE:
 		spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
+		snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
 		break;
 	case HDA_FIXUP_ACT_PROBE:
 		spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
@@ -411,15 +410,11 @@
 			    struct hda_jack_callback *jack)
 {
 	struct conexant_spec *spec = codec->spec;
-	int saved_cached_write = codec->cached_write;
 
-	codec->cached_write = 1;
 	/* in DC mode, we don't handle automic */
 	if (!spec->dc_enable)
 		snd_hda_gen_mic_autoswitch(codec, jack);
 	olpc_xo_update_mic_pins(codec);
-	snd_hda_codec_flush_cache(codec);
-	codec->cached_write = saved_cached_write;
 	if (spec->dc_enable)
 		olpc_xo_update_mic_boost(codec);
 }
@@ -848,7 +843,7 @@
 	struct conexant_spec *spec;
 	int err;
 
-	codec_info(codec, "%s: BIOS auto-probing.\n", codec->chip_name);
+	codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
@@ -862,7 +857,7 @@
 	if (spec->dynamic_eapd)
 		spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x14f15045:
 		codec->single_adc_amp = 1;
 		spec->gen.mixer_nid = 0x17;
@@ -896,7 +891,7 @@
 	 * others may use EAPD really as an amp switch, so it might be
 	 * not good to expose it blindly.
 	 */
-	switch (codec->subsystem_id >> 16) {
+	switch (codec->core.subsystem_id >> 16) {
 	case 0x103c:
 		spec->gen.vmaster_mute_enum = 1;
 		break;
@@ -919,10 +914,10 @@
 	 * which falls into the single-cmd mode.
 	 * Better to make reset, then.
 	 */
-	if (!codec->bus->sync_write) {
+	if (!codec->bus->core.sync_write) {
 		codec_info(codec,
 			   "Enable sync_write for stable communication\n");
-		codec->bus->sync_write = 1;
+		codec->bus->core.sync_write = 1;
 		codec->bus->allow_bus_reset = 1;
 	}
 
@@ -1018,20 +1013,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
 
-static struct hda_codec_preset_list conexant_list = {
+static struct hda_codec_driver conexant_driver = {
 	.preset = snd_hda_preset_conexant,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_conexant_init(void)
-{
-	return snd_hda_add_codec_preset(&conexant_list);
-}
-
-static void __exit patch_conexant_exit(void)
-{
-	snd_hda_delete_codec_preset(&conexant_list);
-}
-
-module_init(patch_conexant_init)
-module_exit(patch_conexant_exit)
+module_hda_codec_driver(conexant_driver);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index b422e40..5f44f60 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -45,14 +45,14 @@
 module_param(static_hdmi_pcm, bool, 0644);
 MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 
-#define is_haswell(codec)  ((codec)->vendor_id == 0x80862807)
-#define is_broadwell(codec)    ((codec)->vendor_id == 0x80862808)
-#define is_skylake(codec) ((codec)->vendor_id == 0x80862809)
+#define is_haswell(codec)  ((codec)->core.vendor_id == 0x80862807)
+#define is_broadwell(codec)    ((codec)->core.vendor_id == 0x80862808)
+#define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809)
 #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
 					|| is_skylake(codec))
 
-#define is_valleyview(codec) ((codec)->vendor_id == 0x80862882)
-#define is_cherryview(codec) ((codec)->vendor_id == 0x80862883)
+#define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
+#define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
 #define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec))
 
 struct hdmi_spec_per_cvt {
@@ -86,7 +86,6 @@
 	bool non_pcm;
 	bool chmap_set;		/* channel-map override by ALSA API? */
 	unsigned char chmap[8]; /* ALSA API channel-map */
-	char pcm_name[8];	/* filled in build_pcm callbacks */
 #ifdef CONFIG_PROC_FS
 	struct snd_info_entry *proc_entry;
 #endif
@@ -132,7 +131,7 @@
 
 	int num_pins;
 	struct snd_array pins; /* struct hdmi_spec_per_pin */
-	struct snd_array pcm_rec; /* struct hda_pcm */
+	struct hda_pcm *pcm_rec[16];
 	unsigned int channels_max; /* max over all cvts */
 
 	struct hdmi_eld temp_eld;
@@ -355,8 +354,7 @@
 	((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
 #define get_cvt(spec, idx) \
 	((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
-#define get_pcm_rec(spec, idx) \
-	((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
+#define get_pcm_rec(spec, idx)	((spec)->pcm_rec[idx])
 
 static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
 {
@@ -579,7 +577,7 @@
 	int err;
 
 	snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
-	err = snd_card_proc_new(codec->bus->card, name, &entry);
+	err = snd_card_proc_new(codec->card, name, &entry);
 	if (err < 0)
 		return err;
 
@@ -594,7 +592,7 @@
 static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
 {
 	if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) {
-		snd_device_free(per_pin->codec->bus->card, per_pin->proc_entry);
+		snd_device_free(per_pin->codec->card, per_pin->proc_entry);
 		per_pin->proc_entry = NULL;
 	}
 }
@@ -1393,13 +1391,12 @@
 			hda_nid_t pin_nid, int mux_idx)
 {
 	struct hdmi_spec *spec = codec->spec;
-	hda_nid_t nid, end_nid;
+	hda_nid_t nid;
 	int cvt_idx, curr;
 	struct hdmi_spec_per_cvt *per_cvt;
 
 	/* configure all pins, including "no physical connection" ones */
-	end_nid = codec->start_nid + codec->num_nodes;
-	for (nid = codec->start_nid; nid < end_nid; nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		unsigned int wid_caps = get_wcaps(codec, nid);
 		unsigned int wid_type = get_wcaps_type(wid_caps);
 
@@ -1548,7 +1545,7 @@
 	bool eld_changed = false;
 	bool ret;
 
-	snd_hda_power_up(codec);
+	snd_hda_power_up_pm(codec);
 	present = snd_hda_pin_sense(codec, pin_nid);
 
 	mutex_lock(&per_pin->lock);
@@ -1578,9 +1575,8 @@
 			update_eld = true;
 		}
 		else if (repoll) {
-			queue_delayed_work(codec->bus->workq,
-					   &per_pin->work,
-					   msecs_to_jiffies(300));
+			schedule_delayed_work(&per_pin->work,
+					      msecs_to_jiffies(300));
 			goto unlock;
 		}
 	}
@@ -1624,7 +1620,7 @@
 	}
 
 	if (eld_changed)
-		snd_ctl_notify(codec->bus->card,
+		snd_ctl_notify(codec->card,
 			       SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
 			       &per_pin->eld_ctl->id);
  unlock:
@@ -1635,7 +1631,7 @@
 		jack->block_report = !ret;
 
 	mutex_unlock(&per_pin->lock);
-	snd_hda_power_down(codec);
+	snd_hda_power_down_pm(codec);
 	return ret;
 }
 
@@ -1731,7 +1727,7 @@
 	hda_nid_t nid;
 	int i, nodes;
 
-	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+	nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &nid);
 	if (!nid || nodes < 0) {
 		codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
 		return -EINVAL;
@@ -2056,11 +2052,10 @@
 		struct hdmi_spec_per_pin *per_pin;
 
 		per_pin = get_pin(spec, pin_idx);
-		sprintf(per_pin->pcm_name, "HDMI %d", pin_idx);
-		info = snd_array_new(&spec->pcm_rec);
+		info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
 		if (!info)
 			return -ENOMEM;
-		info->name = per_pin->pcm_name;
+		spec->pcm_rec[pin_idx] = info;
 		info->pcm_type = HDA_PCM_TYPE_HDMI;
 		info->own_chmap = true;
 
@@ -2070,9 +2065,6 @@
 		/* other pstr fields are set in open */
 	}
 
-	codec->num_pcms = spec->num_pins;
-	codec->pcm_info = spec->pcm_rec.list;
-
 	return 0;
 }
 
@@ -2125,13 +2117,15 @@
 
 	/* add channel maps */
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hda_pcm *pcm;
 		struct snd_pcm_chmap *chmap;
 		struct snd_kcontrol *kctl;
 		int i;
 
-		if (!codec->pcm_info[pin_idx].pcm)
+		pcm = spec->pcm_rec[pin_idx];
+		if (!pcm || !pcm->pcm)
 			break;
-		err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
+		err = snd_pcm_add_chmap_ctls(pcm->pcm,
 					     SNDRV_PCM_STREAM_PLAYBACK,
 					     NULL, 0, pin_idx, &chmap);
 		if (err < 0)
@@ -2186,14 +2180,12 @@
 {
 	snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
 	snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
-	snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums);
 }
 
 static void hdmi_array_free(struct hdmi_spec *spec)
 {
 	snd_array_free(&spec->pins);
 	snd_array_free(&spec->cvts);
-	snd_array_free(&spec->pcm_rec);
 }
 
 static void generic_hdmi_free(struct hda_codec *codec)
@@ -2204,11 +2196,10 @@
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 
-		cancel_delayed_work(&per_pin->work);
+		cancel_delayed_work_sync(&per_pin->work);
 		eld_proc_free(per_pin);
 	}
 
-	flush_workqueue(codec->bus->workq);
 	hdmi_array_free(spec);
 	kfree(spec);
 }
@@ -2220,8 +2211,7 @@
 	int pin_idx;
 
 	codec->patch_ops.init(codec);
-	snd_hda_codec_resume_amp(codec);
-	snd_hda_codec_resume_cache(codec);
+	regcache_sync(codec->core.regmap);
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -2308,6 +2298,7 @@
 
 	/* enable DP1.2 mode */
 	vendor_param |= INTEL_EN_DP12;
+	snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
 	snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0,
 				INTEL_SET_VENDOR_VERB, vendor_param);
 }
@@ -2381,11 +2372,10 @@
 	chans = get_wcaps(codec, per_cvt->cvt_nid);
 	chans = get_wcaps_channels(chans);
 
-	info = snd_array_new(&spec->pcm_rec);
+	info = snd_hda_codec_pcm_new(codec, "HDMI 0");
 	if (!info)
 		return -ENOMEM;
-	info->name = get_pin(spec, 0)->pcm_name;
-	sprintf(info->name, "HDMI 0");
+	spec->pcm_rec[0] = info;
 	info->pcm_type = HDA_PCM_TYPE_HDMI;
 	pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
 	*pstr = spec->pcm_playback;
@@ -2393,9 +2383,6 @@
 	if (pstr->channels_max <= 2 && chans && chans <= 16)
 		pstr->channels_max = chans;
 
-	codec->num_pcms = 1;
-	codec->pcm_info = info;
-
 	return 0;
 }
 
@@ -2940,7 +2927,8 @@
  */
 
 #define is_amdhdmi_rev3_or_later(codec) \
-	((codec)->vendor_id == 0x1002aa01 && ((codec)->revision_id & 0xff00) >= 0x0300)
+	((codec)->core.vendor_id == 0x1002aa01 && \
+	 ((codec)->core.revision_id & 0xff00) >= 0x0300)
 #define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
 
 /* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
@@ -3301,15 +3289,6 @@
 }
 
 /*
- * called from hda_codec.c for generic HDMI support
- */
-int snd_hda_parse_hdmi_codec(struct hda_codec *codec)
-{
-	return patch_generic_hdmi(codec);
-}
-EXPORT_SYMBOL_GPL(snd_hda_parse_hdmi_codec);
-
-/*
  * patch entries
  */
 static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
@@ -3373,6 +3352,8 @@
 { .id = 0x80862882, .name = "Valleyview2 HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862883, .name = "Braswell HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",	.patch = patch_generic_hdmi },
+/* special ID for generic HDMI */
+{ .id = HDA_CODEC_ID_GENERIC_HDMI, .patch = patch_generic_hdmi },
 {} /* terminator */
 };
 
@@ -3442,20 +3423,8 @@
 MODULE_ALIAS("snd-hda-codec-nvhdmi");
 MODULE_ALIAS("snd-hda-codec-atihdmi");
 
-static struct hda_codec_preset_list intel_list = {
+static struct hda_codec_driver hdmi_driver = {
 	.preset = snd_hda_preset_hdmi,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_hdmi_init(void)
-{
-	return snd_hda_add_codec_preset(&intel_list);
-}
-
-static void __exit patch_hdmi_exit(void)
-{
-	snd_hda_delete_codec_preset(&intel_list);
-}
-
-module_init(patch_hdmi_init)
-module_exit(patch_hdmi_exit)
+module_hda_codec_driver(hdmi_driver);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7438213..b18b9c6 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -299,7 +299,7 @@
 
 	coef = alc_get_coef0(codec);
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0262:
 		alc_update_coef_idx(codec, 0x7, 0, 1<<5);
 		break;
@@ -432,7 +432,7 @@
 		snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
 		break;
 	case ALC_INIT_DEFAULT:
-		switch (codec->vendor_id) {
+		switch (codec->core.vendor_id) {
 		case 0x10ec0260:
 			alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
 			break;
@@ -498,18 +498,18 @@
 
 	if (!codec->bus->pci)
 		return -1;
-	ass = codec->subsystem_id & 0xffff;
+	ass = codec->core.subsystem_id & 0xffff;
 	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
 		goto do_sku;
 
 	nid = 0x1d;
-	if (codec->vendor_id == 0x10ec0260)
+	if (codec->core.vendor_id == 0x10ec0260)
 		nid = 0x17;
 	ass = snd_hda_codec_get_pincfg(codec, nid);
 
 	if (!(ass & 1)) {
 		codec_info(codec, "%s: SKU not ready 0x%08x\n",
-			   codec->chip_name, ass);
+			   codec->core.chip_name, ass);
 		return -1;
 	}
 
@@ -585,7 +585,7 @@
 		goto do_sku;
 	}
 
-	ass = codec->subsystem_id & 0xffff;
+	ass = codec->core.subsystem_id & 0xffff;
 	if (codec->bus->pci &&
 	    ass != codec->bus->pci->subsystem_device && (ass & 1))
 		goto do_sku;
@@ -600,7 +600,7 @@
 	 * 0		: override
 	*/
 	nid = 0x1d;
-	if (codec->vendor_id == 0x10ec0260)
+	if (codec->core.vendor_id == 0x10ec0260)
 		nid = 0x17;
 	ass = snd_hda_codec_get_pincfg(codec, nid);
 	codec_dbg(codec,
@@ -621,7 +621,7 @@
 		return 0;
 do_sku:
 	codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
-		   ass & 0xffff, codec->vendor_id);
+		   ass & 0xffff, codec->core.vendor_id);
 	/*
 	 * 0 : override
 	 * 1 :	Swap Jack
@@ -799,8 +799,7 @@
 	if (!spec->no_depop_delay)
 		msleep(150); /* to avoid pop noise */
 	codec->patch_ops.init(codec);
-	snd_hda_codec_resume_amp(codec);
-	snd_hda_codec_resume_cache(codec);
+	regcache_sync(codec->core.regmap);
 	hda_call_check_power_status(codec, 0x01);
 	return 0;
 }
@@ -826,9 +825,9 @@
 /* replace the codec chip_name with the given string */
 static int alc_codec_rename(struct hda_codec *codec, const char *name)
 {
-	kfree(codec->chip_name);
-	codec->chip_name = kstrdup(name, GFP_KERNEL);
-	if (!codec->chip_name) {
+	kfree(codec->core.chip_name);
+	codec->core.chip_name = kstrdup(name, GFP_KERNEL);
+	if (!codec->core.chip_name) {
 		alc_free(codec);
 		return -ENOMEM;
 	}
@@ -904,7 +903,7 @@
 	const struct alc_codec_rename_pci_table *q;
 
 	for (p = rename_tbl; p->vendor_id; p++) {
-		if (p->vendor_id != codec->vendor_id)
+		if (p->vendor_id != codec->core.vendor_id)
 			continue;
 		if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
 			return alc_codec_rename(codec, p->name);
@@ -913,7 +912,7 @@
 	if (!codec->bus->pci)
 		return 0;
 	for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
-		if (q->codec_vendor_id != codec->vendor_id)
+		if (q->codec_vendor_id != codec->core.vendor_id)
 			continue;
 		if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
 			continue;
@@ -1785,7 +1784,7 @@
 {
 	unsigned int gpiostate, gpiomask, gpiodir;
 
-	gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+	gpiostate = snd_hda_codec_read(codec, codec->core.afg, 0,
 				       AC_VERB_GET_GPIO_DATA, 0);
 
 	if (!muted)
@@ -1793,23 +1792,23 @@
 	else
 		gpiostate &= ~(1 << pin);
 
-	gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+	gpiomask = snd_hda_codec_read(codec, codec->core.afg, 0,
 				      AC_VERB_GET_GPIO_MASK, 0);
 	gpiomask |= (1 << pin);
 
-	gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+	gpiodir = snd_hda_codec_read(codec, codec->core.afg, 0,
 				     AC_VERB_GET_GPIO_DIRECTION, 0);
 	gpiodir |= (1 << pin);
 
 
-	snd_hda_codec_write(codec, codec->afg, 0,
+	snd_hda_codec_write(codec, codec->core.afg, 0,
 			    AC_VERB_SET_GPIO_MASK, gpiomask);
-	snd_hda_codec_write(codec, codec->afg, 0,
+	snd_hda_codec_write(codec, codec->core.afg, 0,
 			    AC_VERB_SET_GPIO_DIRECTION, gpiodir);
 
 	msleep(1);
 
-	snd_hda_codec_write(codec, codec->afg, 0,
+	snd_hda_codec_write(codec, codec->core.afg, 0,
 			    AC_VERB_SET_GPIO_DATA, gpiostate);
 }
 
@@ -2269,7 +2268,7 @@
 
 	spec = codec->spec;
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0882:
 	case 0x10ec0885:
 	case 0x10ec0900:
@@ -2602,53 +2601,12 @@
  * ALC269
  */
 
-static int playback_pcm_open(struct hda_pcm_stream *hinfo,
-			     struct hda_codec *codec,
-			     struct snd_pcm_substream *substream)
-{
-	struct hda_gen_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-					     hinfo);
-}
-
-static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-				struct hda_codec *codec,
-				unsigned int stream_tag,
-				unsigned int format,
-				struct snd_pcm_substream *substream)
-{
-	struct hda_gen_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
-						stream_tag, format, substream);
-}
-
-static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-				struct hda_codec *codec,
-				struct snd_pcm_substream *substream)
-{
-	struct hda_gen_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
 static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 8,
 	.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-	/* NID is set in alc_build_pcms */
-	.ops = {
-		.open = playback_pcm_open,
-		.prepare = playback_pcm_prepare,
-		.cleanup = playback_pcm_cleanup
-	},
 };
 
 static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
 	.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-	/* NID is set in alc_build_pcms */
 };
 
 /* different alc269-variants */
@@ -2912,6 +2870,8 @@
 
 	if (!hp_pin)
 		return;
+
+	msleep(30);
 	hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
 
 	/* Index 0x43 Direct Drive HP AMP LPM Control 1 */
@@ -3099,8 +3059,7 @@
 		msleep(200);
 	}
 
-	snd_hda_codec_resume_amp(codec);
-	snd_hda_codec_resume_cache(codec);
+	regcache_sync(codec->core.regmap);
 	hda_call_check_power_status(codec, 0x01);
 
 	/* on some machine, the BIOS will clear the codec gpio data when enter
@@ -3108,7 +3067,7 @@
 	 * in the driver.
 	 */
 	if (spec->gpio_led)
-		snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DATA,
+		snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA,
 			    spec->gpio_led);
 
 	if (spec->has_alc5505_dsp)
@@ -3153,8 +3112,8 @@
 	};
 	unsigned int cfg;
 
-	if (strcmp(codec->chip_name, "ALC271X") &&
-	    strcmp(codec->chip_name, "ALC269VB"))
+	if (strcmp(codec->core.chip_name, "ALC271X") &&
+	    strcmp(codec->core.chip_name, "ALC269VB"))
 		return;
 	cfg = snd_hda_codec_get_pincfg(codec, 0x12);
 	if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
@@ -3264,7 +3223,7 @@
 	snd_hda_set_pin_ctl(codec, nid,
 			    snd_hda_codec_get_pin_target(codec, nid));
 
-	return AC_PWRST_D0;
+	return snd_hda_gen_path_power_filter(codec, nid, power_state);
 }
 
 static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
@@ -3520,9 +3479,9 @@
 		}
 
 		snd_hda_add_verbs(codec, gpio_init);
-		snd_hda_codec_write_cache(codec, codec->afg, 0,
+		snd_hda_codec_write_cache(codec, codec->core.afg, 0,
 					  AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
-		snd_hda_jack_detect_enable_callback(codec, codec->afg,
+		snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
 						    gpio2_mic_hotkey_event);
 
 		spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
@@ -3583,6 +3542,14 @@
 		WRITE_COEF(0x32, 0x42a3),
 		{}
 	};
+	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
 	static struct coef_fw coef0292[] = {
 		WRITE_COEF(0x76, 0x000e),
 		WRITE_COEF(0x6c, 0x2400),
@@ -3605,14 +3572,19 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
+	case 0x10ec0256:
 		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
 		alc_process_coef_fw(codec, coef0233);
 		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_process_coef_fw(codec, coef0288);
+		break;
 	case 0x10ec0292:
 		alc_process_coef_fw(codec, coef0292);
 		break;
@@ -3642,6 +3614,14 @@
 		WRITE_COEF(0x26, 0x008c),
 		{}
 	};
+	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x50, 0x2000, 0),
+		UPDATE_COEF(0x56, 0x0006, 0),
+		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+		UPDATE_COEF(0x66, 0x0008, 0x0008),
+		UPDATE_COEF(0x67, 0x2000, 0x2000),
+		{}
+	};
 	static struct coef_fw coef0292[] = {
 		WRITE_COEF(0x19, 0xa208),
 		WRITE_COEF(0x2e, 0xacf0),
@@ -3660,8 +3640,9 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
+	case 0x10ec0256:
 		alc_write_coef_idx(codec, 0x45, 0xc489);
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
 		alc_process_coef_fw(codec, coef0255);
@@ -3674,6 +3655,13 @@
 		alc_process_coef_fw(codec, coef0233);
 		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
 		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_update_coef_idx(codec, 0x4f, 0x000c, 0);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0288);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
 	case 0x10ec0292:
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
 		alc_process_coef_fw(codec, coef0292);
@@ -3709,6 +3697,14 @@
 		WRITE_COEF(0x32, 0x4ea3),
 		{}
 	};
+	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
 	static struct coef_fw coef0292[] = {
 		WRITE_COEF(0x76, 0x000e),
 		WRITE_COEF(0x6c, 0x2400),
@@ -3729,14 +3725,20 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
+	case 0x10ec0256:
 		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
 		alc_process_coef_fw(codec, coef0233);
 		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_process_coef_fw(codec, coef0288);
+		break;
+		break;
 	case 0x10ec0292:
 		alc_process_coef_fw(codec, coef0292);
 		break;
@@ -3765,6 +3767,13 @@
 		WRITE_COEF(0x32, 0x4ea3),
 		{}
 	};
+	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
 	static struct coef_fw coef0292[] = {
 		WRITE_COEF(0x6b, 0xd429),
 		WRITE_COEF(0x76, 0x0008),
@@ -3783,14 +3792,21 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
+	case 0x10ec0256:
 		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
 		alc_process_coef_fw(codec, coef0233);
 		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+		msleep(300);
+		alc_process_coef_fw(codec, coef0288);
+		break;
 	case 0x10ec0292:
 		alc_process_coef_fw(codec, coef0292);
 		break;
@@ -3819,6 +3835,13 @@
 		WRITE_COEF(0x32, 0x4ea3),
 		{}
 	};
+	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
 	static struct coef_fw coef0292[] = {
 		WRITE_COEF(0x6b, 0xe429),
 		WRITE_COEF(0x76, 0x0008),
@@ -3837,14 +3860,21 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
+	case 0x10ec0256:
 		alc_process_coef_fw(codec, coef0255);
 		break;
 	case 0x10ec0233:
 	case 0x10ec0283:
 		alc_process_coef_fw(codec, coef0233);
 		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+		msleep(300);
+		alc_process_coef_fw(codec, coef0288);
+		break;
 	case 0x10ec0292:
 		alc_process_coef_fw(codec, coef0292);
 		break;
@@ -3869,6 +3899,10 @@
  conteol) */
 		{}
 	};
+	static struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
+		{}
+	};
 	static struct coef_fw coef0293[] = {
 		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
 		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
@@ -3882,8 +3916,9 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
+	case 0x10ec0256:
 		alc_process_coef_fw(codec, coef0255);
 		msleep(300);
 		val = alc_read_coef_idx(codec, 0x46);
@@ -3896,6 +3931,13 @@
 		val = alc_read_coef_idx(codec, 0x46);
 		is_ctia = (val & 0x0070) == 0x0070;
 		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_process_coef_fw(codec, coef0288);
+		msleep(350);
+		val = alc_read_coef_idx(codec, 0x50);
+		is_ctia = (val & 0x0070) == 0x0070;
+		break;
 	case 0x10ec0292:
 		alc_write_coef_idx(codec, 0x6b, 0xd429);
 		msleep(300);
@@ -4079,6 +4121,29 @@
 		alc_fixup_headset_mode(codec, fix, action);
 }
 
+static void alc288_update_headset_jack_cb(struct hda_codec *codec,
+				       struct hda_jack_callback *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	int present;
+
+	alc_update_headset_jack_cb(codec, jack);
+	/* Headset Mic enable or disable, only for Dell Dino */
+	present = spec->gen.hp_jack_present ? 0x40 : 0;
+	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				present);
+}
+
+static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	alc_fixup_headset_mode(codec, fix, action);
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		struct alc_spec *spec = codec->spec;
+		spec->gen.hp_automute_hook = alc288_update_headset_jack_cb;
+	}
+}
+
 static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
 					const struct hda_fixup *fix, int action)
 {
@@ -4119,9 +4184,9 @@
 
 	/* Avoid pop noises when headphones are plugged in */
 	if (spec->gen.hp_jack_present)
-		if (nid == codec->afg || nid == 0x02 || nid == 0x15)
+		if (nid == codec->core.afg || nid == 0x02 || nid == 0x15)
 			return AC_PWRST_D0;
-	return power_state;
+	return snd_hda_gen_path_power_filter(codec, nid, power_state);
 }
 
 static void alc_fixup_dell_xps13(struct hda_codec *codec,
@@ -4364,6 +4429,7 @@
 	ALC269_FIXUP_QUANTA_MUTE,
 	ALC269_FIXUP_LIFEBOOK,
 	ALC269_FIXUP_LIFEBOOK_EXTMIC,
+	ALC269_FIXUP_LIFEBOOK_HP_PIN,
 	ALC269_FIXUP_AMIC,
 	ALC269_FIXUP_DMIC,
 	ALC269VB_FIXUP_AMIC,
@@ -4418,6 +4484,9 @@
 	ALC286_FIXUP_HP_GPIO_LED,
 	ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
 	ALC280_FIXUP_HP_DOCK_PINS,
+	ALC288_FIXUP_DELL_HEADSET_MODE,
+	ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
+	ALC288_FIXUP_DELL_XPS_13_GPIO6,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4517,6 +4586,13 @@
 			{ }
 		},
 	},
+	[ALC269_FIXUP_LIFEBOOK_HP_PIN] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x21, 0x0221102f }, /* HP out */
+			{ }
+		},
+	},
 	[ALC269_FIXUP_AMIC] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -4906,6 +4982,33 @@
 		.chained = true,
 		.chain_id = ALC280_FIXUP_HP_GPIO4
 	},
+	[ALC288_FIXUP_DELL_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_dell_alc288,
+		.chained = true,
+		.chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
+	},
+	[ALC288_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+			{ 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC288_FIXUP_DELL_HEADSET_MODE
+	},
+	[ALC288_FIXUP_DELL_XPS_13_GPIO6] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{0x01, AC_VERB_SET_GPIO_MASK, 0x40},
+			{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x40},
+			{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5010,6 +5113,7 @@
 	SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX),
 	SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
+	SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
 	SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
 	SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC),
@@ -5030,12 +5134,14 @@
 	SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
 	SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -5132,6 +5238,13 @@
 	{0x1b, 0x411111f0}, \
 	{0x1e, 0x411111f0}
 
+#define ALC288_STANDARD_PINS \
+	{0x17, 0x411111f0}, \
+	{0x18, 0x411111f0}, \
+	{0x19, 0x411111f0}, \
+	{0x1a, 0x411111f0}, \
+	{0x1e, 0x411111f0}
+
 #define ALC290_STANDARD_PINS \
 	{0x12, 0x99a30130}, \
 	{0x13, 0x40000000}, \
@@ -5217,6 +5330,16 @@
 		{0x17, 0x40000000},
 		{0x1d, 0x40700001},
 		{0x21, 0x02211050}),
+	SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		{0x12, 0x90a60140},
+		{0x13, 0x40000000},
+		{0x14, 0x90170110},
+		{0x19, 0x411111f0},
+		{0x1a, 0x411111f0},
+		{0x1b, 0x411111f0},
+		{0x1d, 0x40700001},
+		{0x1e, 0x411111f0},
+		{0x21, 0x02211020}),
 	SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
 		{0x12, 0x90a60130},
 		{0x13, 0x40000000},
@@ -5317,6 +5440,13 @@
 		{0x19, 0x03a11020},
 		{0x1d, 0x40e00001},
 		{0x21, 0x0321101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL_XPS_13_GPIO6,
+		ALC288_STANDARD_PINS,
+		{0x12, 0x90a60120},
+		{0x13, 0x40000000},
+		{0x14, 0x90170110},
+		{0x1d, 0x4076832d},
+		{0x21, 0x0321101f}),
 	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
 		ALC290_STANDARD_PINS,
 		{0x14, 0x411111f0},
@@ -5457,6 +5587,7 @@
 
 	spec = codec->spec;
 	spec->gen.shared_mic_vref_pin = 0x18;
+	codec->power_save_node = 1;
 
 	snd_hda_pick_fixup(codec, alc269_fixup_models,
 		       alc269_fixup_tbl, alc269_fixups);
@@ -5470,7 +5601,7 @@
 	if (has_cdefine_beep(codec))
 		spec->gen.beep_nid = 0x01;
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0269:
 		spec->codec_variant = ALC269_TYPE_ALC269VA;
 		switch (alc_get_coef0(codec) & 0x00f0) {
@@ -5553,6 +5684,7 @@
 		set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
 	codec->patch_ops = alc_patch_ops;
+	codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
 #ifdef CONFIG_PM
 	codec->patch_ops.suspend = alc269_suspend;
 	codec->patch_ops.resume = alc269_resume;
@@ -5814,9 +5946,9 @@
 	static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
 	const hda_nid_t *ssids;
 
-	if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
-	    codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 ||
-	    codec->vendor_id == 0x10ec0671)
+	if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
+	    codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
+	    codec->core.vendor_id == 0x10ec0671)
 		ssids = alc663_ssids;
 	else
 		ssids = alc662_ssids;
@@ -5851,7 +5983,7 @@
 {
 	if (action == HDA_FIXUP_ACT_BUILD) {
 		struct alc_spec *spec = codec->spec;
-		spec->gen.pcm_rec[0].stream[0].chmap = asus_pcm_2_1_chmaps;
+		spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
 	}
 }
 
@@ -5861,7 +5993,7 @@
 					  unsigned int power_state)
 {
 	struct alc_spec *spec = codec->spec;
-	if (nid == codec->afg && power_state == AC_PWRST_D3 && spec->gpio_led)
+	if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_led)
 		return AC_PWRST_D0;
 	return power_state;
 }
@@ -6359,7 +6491,7 @@
 
 	alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0668:
 		spec->init_hook = alc668_restore_default_value;
 		break;
@@ -6389,7 +6521,7 @@
 		goto error;
 
 	if (!spec->gen.no_analog && spec->gen.beep_nid) {
-		switch (codec->vendor_id) {
+		switch (codec->core.vendor_id) {
 		case 0x10ec0662:
 			set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 			break;
@@ -6522,20 +6654,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek HD-audio codec");
 
-static struct hda_codec_preset_list realtek_list = {
+static struct hda_codec_driver realtek_driver = {
 	.preset = snd_hda_preset_realtek,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_realtek_init(void)
-{
-	return snd_hda_add_codec_preset(&realtek_list);
-}
-
-static void __exit patch_realtek_exit(void)
-{
-	snd_hda_delete_codec_preset(&realtek_list);
-}
-
-module_init(patch_realtek_init)
-module_exit(patch_realtek_exit)
+module_hda_codec_driver(realtek_driver);
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 3208ad6..5104beb 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -83,7 +83,6 @@
 
 struct si3054_spec {
 	unsigned international;
-	struct hda_pcm pcm;
 };
 
 
@@ -199,15 +198,15 @@
 
 static int si3054_build_pcms(struct hda_codec *codec)
 {
-	struct si3054_spec *spec = codec->spec;
-	struct hda_pcm *info = &spec->pcm;
-	codec->num_pcms = 1;
-	codec->pcm_info = info;
-	info->name = "Si3054 Modem";
+	struct hda_pcm *info;
+
+	info = snd_hda_codec_pcm_new(codec, "Si3054 Modem");
+	if (!info)
+		return -ENOMEM;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->mfg;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->core.mfg;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->core.mfg;
 	info->pcm_type = HDA_PCM_TYPE_MODEM;
 	return 0;
 }
@@ -223,8 +222,12 @@
 	unsigned wait_count;
 	u16 val;
 
+	if (snd_hdac_regmap_add_vendor_verb(&codec->core,
+					    SI3054_VERB_WRITE_NODE))
+		return -ENOMEM;
+
 	snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
-	snd_hda_codec_write(codec, codec->mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+	snd_hda_codec_write(codec, codec->core.mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
 	SET_REG(codec, SI3054_LINE_RATE, 9600);
 	SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
 	SET_REG(codec, SI3054_EXTENDED_MID, 0);
@@ -319,20 +322,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
 
-static struct hda_codec_preset_list si3054_list = {
+static struct hda_codec_driver si3054_driver = {
 	.preset = snd_hda_preset_si3054,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_si3054_init(void)
-{
-	return snd_hda_add_codec_preset(&si3054_list);
-}
-
-static void __exit patch_si3054_exit(void)
-{
-	snd_hda_delete_codec_preset(&si3054_list);
-}
-
-module_init(patch_si3054_init)
-module_exit(patch_si3054_exit)
+module_hda_codec_driver(si3054_driver);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 87eff31..43c99ce 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -299,32 +299,33 @@
 			  unsigned int dir_mask, unsigned int data)
 {
 	unsigned int gpiostate, gpiomask, gpiodir;
+	hda_nid_t fg = codec->core.afg;
 
 	codec_dbg(codec, "%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
 
-	gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+	gpiostate = snd_hda_codec_read(codec, fg, 0,
 				       AC_VERB_GET_GPIO_DATA, 0);
 	gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
 
-	gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+	gpiomask = snd_hda_codec_read(codec, fg, 0,
 				      AC_VERB_GET_GPIO_MASK, 0);
 	gpiomask |= mask;
 
-	gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+	gpiodir = snd_hda_codec_read(codec, fg, 0,
 				     AC_VERB_GET_GPIO_DIRECTION, 0);
 	gpiodir |= dir_mask;
 
 	/* Configure GPIOx as CMOS */
-	snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
+	snd_hda_codec_write(codec, fg, 0, 0x7e7, 0);
 
-	snd_hda_codec_write(codec, codec->afg, 0,
+	snd_hda_codec_write(codec, fg, 0,
 			    AC_VERB_SET_GPIO_MASK, gpiomask);
-	snd_hda_codec_read(codec, codec->afg, 0,
+	snd_hda_codec_read(codec, fg, 0,
 			   AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
 
 	msleep(1);
 
-	snd_hda_codec_read(codec, codec->afg, 0,
+	snd_hda_codec_read(codec, fg, 0,
 			   AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
@@ -387,7 +388,7 @@
 					       hda_nid_t nid,
 					       unsigned int power_state)
 {
-	if (nid == codec->afg && power_state == AC_PWRST_D3)
+	if (nid == codec->core.afg && power_state == AC_PWRST_D3)
 		return AC_PWRST_D1;
 	return snd_hda_gen_path_power_filter(codec, nid, power_state);
 }
@@ -432,7 +433,7 @@
 
 	if (spec->gpio_mute)
 		spec->gen.master_mute =
-			!(snd_hda_codec_read(codec, codec->afg, 0,
+			!(snd_hda_codec_read(codec, codec->core.afg, 0,
 				AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
 
 	snd_hda_gen_update_outputs(codec);
@@ -476,7 +477,7 @@
 	if (val != spec->power_map_bits) {
 		spec->power_map_bits = val;
 		if (do_write)
-			snd_hda_codec_write(codec, codec->afg, 0,
+			snd_hda_codec_write(codec, codec->core.afg, 0,
 					    AC_VERB_IDT_SET_POWER_MAP, val);
 	}
 }
@@ -508,7 +509,8 @@
 				      false);
 	}
 
-	snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP,
+	snd_hda_codec_write(codec, codec->core.afg, 0,
+			    AC_VERB_IDT_SET_POWER_MAP,
 			    spec->power_map_bits);
 }
 
@@ -517,10 +519,10 @@
 {
 	unsigned int data;
 
-	data = snd_hda_codec_read(codec, codec->afg, 0,
+	data = snd_hda_codec_read(codec, codec->core.afg, 0,
 				  AC_VERB_GET_GPIO_DATA, 0);
 	/* toggle VREF state based on GPIOx status */
-	snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
+	snd_hda_codec_write(codec, codec->core.afg, 0, 0x7e0,
 			    !!(data & (1 << event->private_data)));
 }
 
@@ -622,7 +624,7 @@
 	/* Only return the bits defined by the shift value of the
 	 * first two bytes of the mask
 	 */
-	dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
+	dac_mode = snd_hda_codec_read(codec, codec->core.afg, 0,
 				      kcontrol->private_value & 0xFFFF, 0x0);
 	dac_mode >>= spec->aloopback_shift;
 
@@ -634,7 +636,7 @@
 		dac_mode &= ~idx_val;
 	}
 
-	snd_hda_codec_write_cache(codec, codec->afg, 0,
+	snd_hda_codec_write_cache(codec, codec->core.afg, 0,
 		kcontrol->private_value >> 16, dac_mode);
 
 	return 1;
@@ -658,11 +660,11 @@
 /* check whether it's a HP laptop with a docking port */
 static bool hp_bnb2011_with_dock(struct hda_codec *codec)
 {
-	if (codec->vendor_id != 0x111d7605 &&
-	    codec->vendor_id != 0x111d76d1)
+	if (codec->core.vendor_id != 0x111d7605 &&
+	    codec->core.vendor_id != 0x111d76d1)
 		return false;
 
-	switch (codec->subsystem_id) {
+	switch (codec->core.subsystem_id) {
 	case 0x103c1618:
 	case 0x103c1619:
 	case 0x103c161a:
@@ -733,7 +735,7 @@
 	if (spec->gpio_led)
 		return;
 
-	gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+	gpio = snd_hda_param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
 	gpio &= AC_GPIO_IO_COUNT;
 	if (gpio > 3)
 		spec->gpio_led = 0x08; /* GPIO 3 */
@@ -777,7 +779,7 @@
 			   &spec->gpio_led_polarity,
 			   &spec->gpio_led) == 2) {
 			unsigned int max_gpio;
-			max_gpio = snd_hda_param_read(codec, codec->afg,
+			max_gpio = snd_hda_param_read(codec, codec->core.afg,
 						      AC_PAR_GPIO_CAP);
 			max_gpio &= AC_GPIO_IO_COUNT;
 			if (spec->gpio_led < max_gpio)
@@ -807,7 +809,7 @@
 	 * we statically set the GPIO - if not a B-series system
 	 * and default polarity is provided
 	 */
-	if (!hp_blike_system(codec->subsystem_id) &&
+	if (!hp_blike_system(codec->core.subsystem_id) &&
 	    (default_polarity == 0 || default_polarity == 1)) {
 		set_hp_led_gpio(codec);
 		spec->gpio_led_polarity = default_polarity;
@@ -1048,12 +1050,9 @@
 	{}
 };
 
-static const struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+static const hda_nid_t stac92hd71bxx_unmute_nids[] = {
 	/* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
-	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{}
+	0x0f, 0x0a, 0x0d, 0
 };
 
 static const struct hda_verb stac925x_core_init[] = {
@@ -2132,8 +2131,10 @@
 
 	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 		spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+#ifdef CONFIG_PM
 		/* resetting controller clears GPIO, so we need to keep on */
-		codec->bus->power_keep_link_on = 1;
+		codec->core.power_caps &= ~AC_PWRST_CLKSTOP;
+#endif
 	}
 }
 
@@ -3029,9 +3030,9 @@
 		return;
 
 	/* Enable VREF power saving on GPIO1 detect */
-	snd_hda_codec_write_cache(codec, codec->afg, 0,
+	snd_hda_codec_write_cache(codec, codec->core.afg, 0,
 				  AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-	jack = snd_hda_jack_detect_enable_callback(codec, codec->afg,
+	jack = snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
 						   stac_vref_event);
 	if (!IS_ERR(jack))
 		jack->private_data = 0x02;
@@ -3091,7 +3092,7 @@
 	if (action != HDA_FIXUP_ACT_PRE_PROBE)
 		return;
 
-	if (hp_blike_system(codec->subsystem_id)) {
+	if (hp_blike_system(codec->core.subsystem_id)) {
 		unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
 		if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
 			get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER  ||
@@ -3790,7 +3791,7 @@
 	if (action != HDA_FIXUP_ACT_PRE_PROBE)
 		return;
 
-	if (codec->subsystem_id != 0x1028022f) {
+	if (codec->core.subsystem_id != 0x1028022f) {
 		/* GPIO2 High = Enable EAPD */
 		spec->eapd_mask = spec->gpio_mask = 0x04;
 		spec->gpio_dir = spec->gpio_data = 0x04;
@@ -4051,9 +4052,9 @@
 		snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
 
 		/* Enable unsol response for GPIO4/Dock HP connection */
-		snd_hda_codec_write_cache(codec, codec->afg, 0,
+		snd_hda_codec_write_cache(codec, codec->core.afg, 0,
 			AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-		jack = snd_hda_jack_detect_enable_callback(codec, codec->afg,
+		jack = snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
 							   stac_vref_event);
 		if (!IS_ERR(jack))
 			jack->private_data = 0x01;
@@ -4223,6 +4224,12 @@
 	if (err < 0)
 		return err;
 
+	if (spec->vref_mute_led_nid) {
+		err = snd_hda_gen_fix_pin_power(codec, spec->vref_mute_led_nid);
+		if (err < 0)
+			return err;
+	}
+
 	/* setup analog beep controls */
 	if (spec->anabeep_nid > 0) {
 		err = stac_auto_create_beep_ctls(codec,
@@ -4259,6 +4266,10 @@
 
 	if (spec->aloopback_ctl &&
 	    snd_hda_get_bool_hint(codec, "loopback") == 1) {
+		unsigned int wr_verb =
+			spec->aloopback_ctl->private_value >> 16;
+		if (snd_hdac_regmap_add_vendor_verb(&codec->core, wr_verb))
+			return -ENOMEM;
 		if (!snd_hda_gen_add_kctl(&spec->gen, NULL, spec->aloopback_ctl))
 			return -ENOMEM;
 	}
@@ -4294,7 +4305,7 @@
 
 	/* sync the power-map */
 	if (spec->num_pwrs)
-		snd_hda_codec_write(codec, codec->afg, 0,
+		snd_hda_codec_write(codec, codec->core.afg, 0,
 				    AC_VERB_IDT_SET_POWER_MAP,
 				    spec->power_map_bits);
 
@@ -4330,7 +4341,7 @@
 static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
 			       struct hda_codec *codec, hda_nid_t nid)
 {
-	if (nid == codec->afg)
+	if (nid == codec->core.afg)
 		snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
 			    snd_hda_codec_read(codec, nid, 0,
 					       AC_VERB_IDT_GET_POWER_MAP, 0));
@@ -4341,7 +4352,7 @@
 				  unsigned int verb)
 {
 	snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
-		    snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
+		    snd_hda_codec_read(codec, codec->core.afg, 0, verb, 0));
 }
 
 /* stac92hd71bxx, stac92hd73xx */
@@ -4349,21 +4360,21 @@
 				 struct hda_codec *codec, hda_nid_t nid)
 {
 	stac92hd_proc_hook(buffer, codec, nid);
-	if (nid == codec->afg)
+	if (nid == codec->core.afg)
 		analog_loop_proc_hook(buffer, codec, 0xfa0);
 }
 
 static void stac9205_proc_hook(struct snd_info_buffer *buffer,
 			       struct hda_codec *codec, hda_nid_t nid)
 {
-	if (nid == codec->afg)
+	if (nid == codec->core.afg)
 		analog_loop_proc_hook(buffer, codec, 0xfe0);
 }
 
 static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 			       struct hda_codec *codec, hda_nid_t nid)
 {
-	if (nid == codec->afg)
+	if (nid == codec->core.afg)
 		analog_loop_proc_hook(buffer, codec, 0xfeb);
 }
 #else
@@ -4392,6 +4403,7 @@
 #ifdef CONFIG_PM
 	.suspend = stac_suspend,
 #endif
+	.stream_pm = snd_hda_gen_stream_pm,
 	.reboot_notify = stac_shutup,
 };
 
@@ -4485,6 +4497,7 @@
 		return err;
 
 	spec = codec->spec;
+	codec->power_save_node = 1;
 	spec->linear_tone_beep = 0;
 	spec->gen.mixer_nid = 0x1d;
 	spec->have_spdif_mux = 1;
@@ -4587,9 +4600,11 @@
 	if (err < 0)
 		return err;
 
-	codec->epss = 0; /* longer delay needed for D3 */
+	/* longer delay needed for D3 */
+	codec->core.power_caps &= ~AC_PWRST_EPSS;
 
 	spec = codec->spec;
+	codec->power_save_node = 1;
 	spec->linear_tone_beep = 0;
 	spec->gen.own_eapd_ctl = 1;
 	spec->gen.power_down_unused = 1;
@@ -4636,9 +4651,11 @@
 	if (err < 0)
 		return err;
 
-	codec->epss = 0; /* longer delay needed for D3 */
+	/* longer delay needed for D3 */
+	codec->core.power_caps &= ~AC_PWRST_EPSS;
 
 	spec = codec->spec;
+	codec->power_save_node = 1;
 	spec->linear_tone_beep = 0;
 	spec->gen.own_eapd_ctl = 1;
 	spec->gen.power_down_unused = 1;
@@ -4672,7 +4689,7 @@
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
-	const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
+	const hda_nid_t *unmute_nids = stac92hd71bxx_unmute_nids;
 	int err;
 
 	err = alloc_stac_spec(codec);
@@ -4680,6 +4697,7 @@
 		return err;
 
 	spec = codec->spec;
+	codec->power_save_node = 1;
 	spec->linear_tone_beep = 0;
 	spec->gen.own_eapd_ctl = 1;
 	spec->gen.power_down_unused = 1;
@@ -4693,23 +4711,23 @@
 	spec->gpio_dir = 0x01;
 	spec->gpio_data = 0x01;
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x111d76b6: /* 4 Port without Analog Mixer */
 	case 0x111d76b7:
-		unmute_init++;
+		unmute_nids++;
 		break;
 	case 0x111d7608: /* 5 Port with Analog Mixer */
-		if ((codec->revision_id & 0xf) == 0 ||
-		    (codec->revision_id & 0xf) == 1)
+		if ((codec->core.revision_id & 0xf) == 0 ||
+		    (codec->core.revision_id & 0xf) == 1)
 			spec->stream_delay = 40; /* 40 milliseconds */
 
 		/* disable VSW */
-		unmute_init++;
+		unmute_nids++;
 		snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
 		snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
 		break;
 	case 0x111d7603: /* 6 Port with Analog Mixer */
-		if ((codec->revision_id & 0xf) == 1)
+		if ((codec->core.revision_id & 0xf) == 1)
 			spec->stream_delay = 40; /* 40 milliseconds */
 
 		break;
@@ -4718,8 +4736,12 @@
 	if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB)
 		snd_hda_add_verbs(codec, stac92hd71bxx_core_init);
 
-	if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
-		snd_hda_sequence_write_cache(codec, unmute_init);
+	if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) {
+		const hda_nid_t *p;
+		for (p = unmute_nids; *p; p++)
+			snd_hda_codec_amp_init_stereo(codec, *p, HDA_INPUT, 0,
+						      0xff, 0x00);
+	}
 
 	spec->aloopback_ctl = &stac92hd71bxx_loopback;
 	spec->aloopback_mask = 0x50;
@@ -5091,20 +5113,8 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
 
-static struct hda_codec_preset_list sigmatel_list = {
+static struct hda_codec_driver sigmatel_driver = {
 	.preset = snd_hda_preset_sigmatel,
-	.owner = THIS_MODULE,
 };
 
-static int __init patch_sigmatel_init(void)
-{
-	return snd_hda_add_codec_preset(&sigmatel_list);
-}
-
-static void __exit patch_sigmatel_exit(void)
-{
-	snd_hda_delete_codec_preset(&sigmatel_list);
-}
-
-module_init(patch_sigmatel_init)
-module_exit(patch_sigmatel_exit)
+module_hda_codec_driver(sigmatel_driver);
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 3de6d3d..31a95cc 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -99,7 +99,6 @@
 
 	/* HP mode source */
 	unsigned int dmic_enabled;
-	unsigned int no_pin_power_ctl;
 	enum VIA_HDA_CODEC codec_type;
 
 	/* analog low-power control */
@@ -109,8 +108,7 @@
 	int hp_work_active;
 	int vt1708_jack_detect;
 
-	void (*set_widgets_power_state)(struct hda_codec *codec);
-	unsigned int dac_stream_tag[4];
+	unsigned int beep_amp;
 };
 
 static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
@@ -133,17 +131,18 @@
 	/* VT1708BCE & VT1708S are almost same */
 	if (spec->codec_type == VT1708BCE)
 		spec->codec_type = VT1708S;
-	spec->no_pin_power_ctl = 1;
 	spec->gen.indep_hp = 1;
 	spec->gen.keep_eapd_on = 1;
 	spec->gen.pcm_playback_hook = via_playback_pcm_hook;
 	spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+	codec->power_save_node = 1;
+	spec->gen.power_down_unused = 1;
 	return spec;
 }
 
 static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 {
-	u32 vendor_id = codec->vendor_id;
+	u32 vendor_id = codec->core.vendor_id;
 	u16 ven_id = vendor_id >> 16;
 	u16 dev_id = vendor_id & 0xffff;
 	enum VIA_HDA_CODEC codec_type;
@@ -222,98 +221,13 @@
 		if (!spec->hp_work_active) {
 			codec->jackpoll_interval = msecs_to_jiffies(100);
 			snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);
-			queue_delayed_work(codec->bus->workq,
-					   &codec->jackpoll_work, 0);
+			schedule_delayed_work(&codec->jackpoll_work, 0);
 			spec->hp_work_active = true;
 		}
 	} else if (!hp_detect_with_aa(codec))
 		vt1708_stop_hp_work(codec);
 }
 
-static void set_widgets_power_state(struct hda_codec *codec)
-{
-#if 0 /* FIXME: the assumed connections don't match always with the
-       * actual routes by the generic parser, so better to disable
-       * the control for safety.
-       */
-	struct via_spec *spec = codec->spec;
-	if (spec->set_widgets_power_state)
-		spec->set_widgets_power_state(codec);
-#endif
-}
-
-static void update_power_state(struct hda_codec *codec, hda_nid_t nid,
-			       unsigned int parm)
-{
-	if (snd_hda_check_power_state(codec, nid, parm))
-		return;
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
-}
-
-static void update_conv_power_state(struct hda_codec *codec, hda_nid_t nid,
-			       unsigned int parm, unsigned int index)
-{
-	struct via_spec *spec = codec->spec;
-	unsigned int format;
-
-	if (snd_hda_check_power_state(codec, nid, parm))
-		return;
-	format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-	if (format && (spec->dac_stream_tag[index] != format))
-		spec->dac_stream_tag[index] = format;
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
-	if (parm == AC_PWRST_D0) {
-		format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-		if (!format && (spec->dac_stream_tag[index] != format))
-			snd_hda_codec_write(codec, nid, 0,
-						  AC_VERB_SET_CHANNEL_STREAMID,
-						  spec->dac_stream_tag[index]);
-	}
-}
-
-static bool smart51_enabled(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	return spec->gen.ext_channel_count > 2;
-}
-
-static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin)
-{
-	struct via_spec *spec = codec->spec;
-	int i;
-
-	for (i = 0; i < spec->gen.multi_ios; i++)
-		if (spec->gen.multi_io[i].pin == pin)
-			return true;
-	return false;
-}
-
-static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
-				unsigned int *affected_parm)
-{
-	unsigned parm;
-	unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
-	unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
-		>> AC_DEFCFG_MISC_SHIFT
-		& AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
-	struct via_spec *spec = codec->spec;
-	unsigned present = 0;
-
-	no_presence |= spec->no_pin_power_ctl;
-	if (!no_presence)
-		present = snd_hda_jack_detect(codec, nid);
-	if ((smart51_enabled(codec) && is_smart51_pins(codec, nid))
-	    || ((no_presence || present)
-		&& get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
-		*affected_parm = AC_PWRST_D0; /* if it's connected */
-		parm = AC_PWRST_D0;
-	} else
-		parm = AC_PWRST_D3;
-
-	update_power_state(codec, nid, parm);
-}
-
 static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_info *uinfo)
 {
@@ -324,8 +238,7 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct via_spec *spec = codec->spec;
-	ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl;
+	ucontrol->value.enumerated.item[0] = codec->power_save_node;
 	return 0;
 }
 
@@ -334,12 +247,12 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct via_spec *spec = codec->spec;
-	unsigned int val = !ucontrol->value.enumerated.item[0];
+	bool val = !!ucontrol->value.enumerated.item[0];
 
-	if (val == spec->no_pin_power_ctl)
+	if (val == codec->power_save_node)
 		return 0;
-	spec->no_pin_power_ctl = val;
-	set_widgets_power_state(codec);
+	codec->power_save_node = val;
+	spec->gen.power_down_unused = val;
 	analog_low_current_mode(codec);
 	return 1;
 }
@@ -355,6 +268,59 @@
 	{} /* terminator */
 };
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+static inline void set_beep_amp(struct via_spec *spec, hda_nid_t nid,
+				int idx, int dir)
+{
+	spec->gen.beep_nid = nid;
+	spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+}
+
+/* additional beep mixers; the actual parameters are overwritten at build */
+static const struct snd_kcontrol_new cxt_beep_mixer[] = {
+	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+/* create beep controls if needed */
+static int add_beep_ctls(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+
+	if (spec->beep_amp) {
+		const struct snd_kcontrol_new *knew;
+		for (knew = cxt_beep_mixer; knew->name; knew++) {
+			struct snd_kcontrol *kctl;
+			kctl = snd_ctl_new1(knew, codec);
+			if (!kctl)
+				return -ENOMEM;
+			kctl->private_value = spec->beep_amp;
+			err = snd_hda_ctl_add(codec, 0, kctl);
+			if (err < 0)
+				return err;
+		}
+	}
+	return 0;
+}
+
+static void auto_parse_beep(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	hda_nid_t nid;
+
+	for_each_hda_codec_node(nid, codec)
+		if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
+			set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+			break;
+		}
+}
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#define add_beep_ctls(codec)	0
+#define auto_parse_beep(codec)
+#endif
 
 /* check AA path's mute status */
 static bool is_aa_path_mute(struct hda_codec *codec)
@@ -384,7 +350,7 @@
 	bool enable;
 	unsigned int verb, parm;
 
-	if (spec->no_pin_power_ctl)
+	if (!codec->power_save_node)
 		enable = false;
 	else
 		enable = is_aa_path_mute(codec) && !spec->gen.active_streams;
@@ -424,7 +390,7 @@
 		return;		/* other codecs are not supported */
 	}
 	/* send verb */
-	snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
+	snd_hda_codec_write(codec, codec->core.afg, 0, verb, parm);
 }
 
 static void analog_low_current_mode(struct hda_codec *codec)
@@ -441,8 +407,11 @@
 	if (err < 0)
 		return err;
 
-	if (spec->set_widgets_power_state)
-		spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
+	err = add_beep_ctls(codec);
+	if (err < 0)
+		return err;
+
+	spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
 
 	for (i = 0; i < spec->num_mixers; i++) {
 		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -486,7 +455,6 @@
 static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct via_spec *spec = codec->spec;
-	set_widgets_power_state(codec);
 	analog_low_current_mode(codec);
 	vt1708_update_hp_work(codec);
 	return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid);
@@ -504,6 +472,7 @@
 	.init = via_init,
 	.free = via_free,
 	.unsol_event = snd_hda_jack_unsol_event,
+	.stream_pm = snd_hda_gen_stream_pm,
 #ifdef CONFIG_PM
 	.suspend = via_suspend,
 	.check_power_status = via_check_power_status,
@@ -574,34 +543,6 @@
 	{} /* terminator */
 };
 
-static void via_jack_powerstate_event(struct hda_codec *codec,
-				      struct hda_jack_callback *tbl)
-{
-	set_widgets_power_state(codec);
-}
-
-static void via_set_jack_unsol_events(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-	hda_nid_t pin;
-	int i;
-
-	for (i = 0; i < cfg->line_outs; i++) {
-		pin = cfg->line_out_pins[i];
-		if (pin && is_jack_detectable(codec, pin))
-			snd_hda_jack_detect_enable_callback(codec, pin,
-							    via_jack_powerstate_event);
-	}
-
-	for (i = 0; i < cfg->num_inputs; i++) {
-		pin = cfg->line_out_pins[i];
-		if (pin && is_jack_detectable(codec, pin))
-			snd_hda_jack_detect_enable_callback(codec, pin,
-							    via_jack_powerstate_event);
-	}
-}
-
 static const struct badness_table via_main_out_badness = {
 	.no_primary_dac = 0x10000,
 	.no_dac = 0x4000,
@@ -631,11 +572,15 @@
 	if (err < 0)
 		return err;
 
+	auto_parse_beep(codec);
+
 	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
 	if (err < 0)
 		return err;
 
-	via_set_jack_unsol_events(codec);
+	/* disable widget PM at start for compatibility */
+	codec->power_save_node = 0;
+	spec->gen.power_down_unused = 0;
 	return 0;
 }
 
@@ -648,7 +593,6 @@
 		snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
 	/* init power states */
-	set_widgets_power_state(codec);
 	__analog_low_current_mode(codec, true);
 
 	snd_hda_gen_init(codec);
@@ -676,15 +620,17 @@
 	int i, err;
 
 	err = snd_hda_gen_build_pcms(codec);
-	if (err < 0 || codec->vendor_id != 0x11061708)
+	if (err < 0 || codec->core.vendor_id != 0x11061708)
 		return err;
 
 	/* We got noisy outputs on the right channel on VT1708 when
 	 * 24bit samples are used.  Until any workaround is found,
 	 * disable the 24bit format, so far.
 	 */
-	for (i = 0; i < codec->num_pcms; i++) {
-		struct hda_pcm *info = &spec->gen.pcm_rec[i];
+	for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) {
+		struct hda_pcm *info = spec->gen.pcm_rec[i];
+		if (!info)
+			continue;
 		if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams ||
 		    info->pcm_type != HDA_PCM_TYPE_AUDIO)
 			continue;
@@ -766,78 +712,6 @@
 	return 0;
 }
 
-static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm;
-	int is_8ch = 0;
-	if ((spec->codec_type != VT1708B_4CH) &&
-	    (codec->vendor_id != 0x11064397))
-		is_8ch = 1;
-
-	/* SW0 (17h) = stereo mixer */
-	imux_is_smixer =
-	(snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
-	 == ((spec->codec_type == VT1708S) ? 5 : 0));
-	/* inputs */
-	/* PW 1/2/5 (1ah/1bh/1eh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x1a, &parm);
-	set_pin_power_state(codec, 0x1b, &parm);
-	set_pin_power_state(codec, 0x1e, &parm);
-	if (imux_is_smixer)
-		parm = AC_PWRST_D0;
-	/* SW0 (17h), AIW 0/1 (13h/14h) */
-	update_power_state(codec, 0x17, parm);
-	update_power_state(codec, 0x13, parm);
-	update_power_state(codec, 0x14, parm);
-
-	/* outputs */
-	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x19, &parm);
-	if (smart51_enabled(codec))
-		set_pin_power_state(codec, 0x1b, &parm);
-	update_power_state(codec, 0x18, parm);
-	update_power_state(codec, 0x11, parm);
-
-	/* PW6 (22h), SW2 (26h), AOW2 (24h) */
-	if (is_8ch) {
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x22, &parm);
-		if (smart51_enabled(codec))
-			set_pin_power_state(codec, 0x1a, &parm);
-		update_power_state(codec, 0x26, parm);
-		update_power_state(codec, 0x24, parm);
-	} else if (codec->vendor_id == 0x11064397) {
-		/* PW7(23h), SW2(27h), AOW2(25h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x23, &parm);
-		if (smart51_enabled(codec))
-			set_pin_power_state(codec, 0x1a, &parm);
-		update_power_state(codec, 0x27, parm);
-		update_power_state(codec, 0x25, parm);
-	}
-
-	/* PW 3/4/7 (1ch/1dh/23h) */
-	parm = AC_PWRST_D3;
-	/* force to D0 for internal Speaker */
-	set_pin_power_state(codec, 0x1c, &parm);
-	set_pin_power_state(codec, 0x1d, &parm);
-	if (is_8ch)
-		set_pin_power_state(codec, 0x23, &parm);
-
-	/* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
-	update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm);
-	update_power_state(codec, 0x10, parm);
-	if (is_8ch) {
-		update_power_state(codec, 0x25, parm);
-		update_power_state(codec, 0x27, parm);
-	} else if (codec->vendor_id == 0x11064397 && spec->gen.indep_hp_enabled)
-		update_power_state(codec, 0x25, parm);
-}
-
 static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708B(struct hda_codec *codec)
 {
@@ -862,9 +736,6 @@
 	}
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
-
 	return 0;
 }
 
@@ -905,19 +776,19 @@
 
 	/* correct names for VT1708BCE */
 	if (get_codec_type(codec) == VT1708BCE)	{
-		kfree(codec->chip_name);
-		codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
-		snprintf(codec->bus->card->mixername,
-			 sizeof(codec->bus->card->mixername),
-			 "%s %s", codec->vendor_name, codec->chip_name);
+		kfree(codec->core.chip_name);
+		codec->core.chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
+		snprintf(codec->card->mixername,
+			 sizeof(codec->card->mixername),
+			 "%s %s", codec->core.vendor_name, codec->core.chip_name);
 	}
 	/* correct names for VT1705 */
-	if (codec->vendor_id == 0x11064397)	{
-		kfree(codec->chip_name);
-		codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
-		snprintf(codec->bus->card->mixername,
-			 sizeof(codec->bus->card->mixername),
-			 "%s %s", codec->vendor_name, codec->chip_name);
+	if (codec->core.vendor_id == 0x11064397) {
+		kfree(codec->core.chip_name);
+		codec->core.chip_name = kstrdup("VT1705", GFP_KERNEL);
+		snprintf(codec->card->mixername,
+			 sizeof(codec->card->mixername),
+			 "%s %s", codec->core.vendor_name, codec->core.chip_name);
 	}
 
 	/* automatic parse from the BIOS config */
@@ -930,8 +801,6 @@
 	spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 	return 0;
 }
 
@@ -945,36 +814,6 @@
 	{ }
 };
 
-static void set_widgets_power_state_vt1702(struct hda_codec *codec)
-{
-	int imux_is_smixer =
-	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-	unsigned int parm;
-	/* inputs */
-	/* PW 1/2/5 (14h/15h/18h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x14, &parm);
-	set_pin_power_state(codec, 0x15, &parm);
-	set_pin_power_state(codec, 0x18, &parm);
-	if (imux_is_smixer)
-		parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
-	/* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
-	update_power_state(codec, 0x13, parm);
-	update_power_state(codec, 0x12, parm);
-	update_power_state(codec, 0x1f, parm);
-	update_power_state(codec, 0x20, parm);
-
-	/* outputs */
-	/* PW 3/4 (16h/17h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x17, &parm);
-	set_pin_power_state(codec, 0x16, &parm);
-	/* MW0 (1ah), AOW 0/1 (10h/1dh) */
-	update_power_state(codec, 0x1a, imux_is_smixer ? AC_PWRST_D0 : parm);
-	update_power_state(codec, 0x10, parm);
-	update_power_state(codec, 0x1d, parm);
-}
-
 static int patch_vt1702(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -1004,8 +843,6 @@
 	spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
 	return 0;
 }
 
@@ -1020,71 +857,6 @@
 	{ }
 };
 
-static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm, parm2;
-	/* MUX6 (1eh) = stereo mixer */
-	imux_is_smixer =
-	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-	/* inputs */
-	/* PW 5/6/7 (29h/2ah/2bh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x29, &parm);
-	set_pin_power_state(codec, 0x2a, &parm);
-	set_pin_power_state(codec, 0x2b, &parm);
-	if (imux_is_smixer)
-		parm = AC_PWRST_D0;
-	/* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
-	update_power_state(codec, 0x1e, parm);
-	update_power_state(codec, 0x1f, parm);
-	update_power_state(codec, 0x10, parm);
-	update_power_state(codec, 0x11, parm);
-
-	/* outputs */
-	/* PW3 (27h), MW2 (1ah), AOW3 (bh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x27, &parm);
-	update_power_state(codec, 0x1a, parm);
-	parm2 = parm; /* for pin 0x0b */
-
-	/* PW2 (26h), AOW2 (ah) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x26, &parm);
-	if (smart51_enabled(codec))
-		set_pin_power_state(codec, 0x2b, &parm);
-	update_power_state(codec, 0xa, parm);
-
-	/* PW0 (24h), AOW0 (8h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x24, &parm);
-	if (!spec->gen.indep_hp_enabled) /* check for redirected HP */
-		set_pin_power_state(codec, 0x28, &parm);
-	update_power_state(codec, 0x8, parm);
-	if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3)
-		parm = parm2;
-	update_power_state(codec, 0xb, parm);
-	/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-	update_power_state(codec, 0x21, imux_is_smixer ? AC_PWRST_D0 : parm);
-
-	/* PW1 (25h), AOW1 (9h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x25, &parm);
-	if (smart51_enabled(codec))
-		set_pin_power_state(codec, 0x2a, &parm);
-	update_power_state(codec, 0x9, parm);
-
-	if (spec->gen.indep_hp_enabled) {
-		/* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x28, &parm);
-		update_power_state(codec, 0x1b, parm);
-		update_power_state(codec, 0x34, parm);
-		update_power_state(codec, 0xc, parm);
-	}
-}
-
 /* Add a connection to the primary DAC from AA-mixer for some codecs
  * This isn't listed from the raw info, but the chip has a secret connection.
  */
@@ -1105,8 +877,7 @@
 	}
 
 	/* find the primary DAC and add to the connection list */
-	nid = codec->start_nid;
-	for (i = 0; i < codec->num_nodes; i++, nid++) {
+	for_each_hda_codec_node(nid, codec) {
 		unsigned int caps = get_wcaps(codec, nid);
 		if (get_wcaps_type(caps) == AC_WID_AUD_OUT &&
 		    !(caps & AC_WCAP_DIGITAL)) {
@@ -1145,9 +916,6 @@
 	spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
-
 	return 0;
 }
 
@@ -1187,7 +955,6 @@
 	snd_hda_codec_write(codec, 0x26, 0,
 					       AC_VERB_SET_CONNECT_SEL, index);
 	spec->dmic_enabled = index;
-	set_widgets_power_state(codec);
 	return 1;
 }
 
@@ -1222,95 +989,6 @@
 	{ }
 };
 
-static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm;
-	unsigned int mono_out, present;
-	/* SW0 (17h) = stereo mixer */
-	imux_is_smixer =
-	(snd_hda_codec_read(codec, 0x17, 0,
-			    AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
-	/* inputs */
-	/* PW 1/2/5 (1ah/1bh/1eh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x1a, &parm);
-	set_pin_power_state(codec, 0x1b, &parm);
-	set_pin_power_state(codec, 0x1e, &parm);
-	if (imux_is_smixer)
-		parm = AC_PWRST_D0;
-	/* SW0 (17h), AIW0(13h) */
-	update_power_state(codec, 0x17, parm);
-	update_power_state(codec, 0x13, parm);
-
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x1e, &parm);
-	/* PW11 (22h) */
-	if (spec->dmic_enabled)
-		set_pin_power_state(codec, 0x22, &parm);
-	else
-		update_power_state(codec, 0x22, AC_PWRST_D3);
-
-	/* SW2(26h), AIW1(14h) */
-	update_power_state(codec, 0x26, parm);
-	update_power_state(codec, 0x14, parm);
-
-	/* outputs */
-	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x19, &parm);
-	/* Smart 5.1 PW2(1bh) */
-	if (smart51_enabled(codec))
-		set_pin_power_state(codec, 0x1b, &parm);
-	update_power_state(codec, 0x18, parm);
-	update_power_state(codec, 0x11, parm);
-
-	/* PW7 (23h), SW3 (27h), AOW3 (25h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x23, &parm);
-	/* Smart 5.1 PW1(1ah) */
-	if (smart51_enabled(codec))
-		set_pin_power_state(codec, 0x1a, &parm);
-	update_power_state(codec, 0x27, parm);
-
-	/* Smart 5.1 PW5(1eh) */
-	if (smart51_enabled(codec))
-		set_pin_power_state(codec, 0x1e, &parm);
-	update_power_state(codec, 0x25, parm);
-
-	/* Mono out */
-	/* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
-	present = snd_hda_jack_detect(codec, 0x1c);
-
-	if (present)
-		mono_out = 0;
-	else {
-		present = snd_hda_jack_detect(codec, 0x1d);
-		if (!spec->gen.indep_hp_enabled && present)
-			mono_out = 0;
-		else
-			mono_out = 1;
-	}
-	parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
-	update_power_state(codec, 0x28, parm);
-	update_power_state(codec, 0x29, parm);
-	update_power_state(codec, 0x2a, parm);
-
-	/* PW 3/4 (1ch/1dh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x1c, &parm);
-	set_pin_power_state(codec, 0x1d, &parm);
-	/* HP Independent Mode, power on AOW3 */
-	if (spec->gen.indep_hp_enabled)
-		update_power_state(codec, 0x25, parm);
-
-	/* force to D0 for internal Speaker */
-	/* MW0 (16h), AOW0 (10h) */
-	update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm);
-	update_power_state(codec, 0x10, mono_out ? AC_PWRST_D0 : parm);
-}
-
 static int patch_vt1716S(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -1338,8 +1016,6 @@
 	spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
 	return 0;
 }
 
@@ -1365,98 +1041,6 @@
 	{ }
 };
 
-static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm;
-	unsigned int present;
-	/* MUX9 (1eh) = stereo mixer */
-	imux_is_smixer =
-	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-	/* inputs */
-	/* PW 5/6/7 (29h/2ah/2bh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x29, &parm);
-	set_pin_power_state(codec, 0x2a, &parm);
-	set_pin_power_state(codec, 0x2b, &parm);
-	parm = AC_PWRST_D0;
-	/* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
-	update_power_state(codec, 0x1e, parm);
-	update_power_state(codec, 0x1f, parm);
-	update_power_state(codec, 0x10, parm);
-	update_power_state(codec, 0x11, parm);
-
-	/* outputs */
-	/* AOW0 (8h)*/
-	update_power_state(codec, 0x8, parm);
-
-	if (spec->codec_type == VT1802) {
-		/* PW4 (28h), MW4 (18h), MUX4(38h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x28, &parm);
-		update_power_state(codec, 0x18, parm);
-		update_power_state(codec, 0x38, parm);
-	} else {
-		/* PW4 (26h), MW4 (1ch), MUX4(37h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x26, &parm);
-		update_power_state(codec, 0x1c, parm);
-		update_power_state(codec, 0x37, parm);
-	}
-
-	if (spec->codec_type == VT1802) {
-		/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x25, &parm);
-		update_power_state(codec, 0x15, parm);
-		update_power_state(codec, 0x35, parm);
-	} else {
-		/* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x25, &parm);
-		update_power_state(codec, 0x19, parm);
-		update_power_state(codec, 0x35, parm);
-	}
-
-	if (spec->gen.indep_hp_enabled)
-		update_power_state(codec, 0x9, AC_PWRST_D0);
-
-	/* Class-D */
-	/* PW0 (24h), MW0(18h/14h), MUX0(34h) */
-	present = snd_hda_jack_detect(codec, 0x25);
-
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x24, &parm);
-	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
-	if (spec->codec_type == VT1802)
-		update_power_state(codec, 0x14, parm);
-	else
-		update_power_state(codec, 0x18, parm);
-	update_power_state(codec, 0x34, parm);
-
-	/* Mono Out */
-	present = snd_hda_jack_detect(codec, 0x26);
-
-	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
-	if (spec->codec_type == VT1802) {
-		/* PW15 (33h), MW8(1ch), MUX8(3ch) */
-		update_power_state(codec, 0x33, parm);
-		update_power_state(codec, 0x1c, parm);
-		update_power_state(codec, 0x3c, parm);
-	} else {
-		/* PW15 (31h), MW8(17h), MUX8(3bh) */
-		update_power_state(codec, 0x31, parm);
-		update_power_state(codec, 0x17, parm);
-		update_power_state(codec, 0x3b, parm);
-	}
-	/* MW9 (21h) */
-	if (imux_is_smixer || !is_aa_path_mute(codec))
-		update_power_state(codec, 0x21, AC_PWRST_D0);
-	else
-		update_power_state(codec, 0x21, AC_PWRST_D3);
-}
-
 /*
  * pin fix-up
  */
@@ -1540,8 +1124,6 @@
 		spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
 	return 0;
 }
 
@@ -1555,81 +1137,6 @@
 	{ }
 };
 
-static void set_widgets_power_state_vt1812(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	unsigned int parm;
-	unsigned int present;
-	/* inputs */
-	/* PW 5/6/7 (29h/2ah/2bh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x29, &parm);
-	set_pin_power_state(codec, 0x2a, &parm);
-	set_pin_power_state(codec, 0x2b, &parm);
-	parm = AC_PWRST_D0;
-	/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-	update_power_state(codec, 0x1e, parm);
-	update_power_state(codec, 0x1f, parm);
-	update_power_state(codec, 0x10, parm);
-	update_power_state(codec, 0x11, parm);
-
-	/* outputs */
-	/* AOW0 (8h)*/
-	update_power_state(codec, 0x8, AC_PWRST_D0);
-
-	/* PW4 (28h), MW4 (18h), MUX4(38h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x28, &parm);
-	update_power_state(codec, 0x18, parm);
-	update_power_state(codec, 0x38, parm);
-
-	/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x25, &parm);
-	update_power_state(codec, 0x15, parm);
-	update_power_state(codec, 0x35, parm);
-	if (spec->gen.indep_hp_enabled)
-		update_power_state(codec, 0x9, AC_PWRST_D0);
-
-	/* Internal Speaker */
-	/* PW0 (24h), MW0(14h), MUX0(34h) */
-	present = snd_hda_jack_detect(codec, 0x25);
-
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x24, &parm);
-	if (present) {
-		update_power_state(codec, 0x14, AC_PWRST_D3);
-		update_power_state(codec, 0x34, AC_PWRST_D3);
-	} else {
-		update_power_state(codec, 0x14, AC_PWRST_D0);
-		update_power_state(codec, 0x34, AC_PWRST_D0);
-	}
-
-
-	/* Mono Out */
-	/* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
-	present = snd_hda_jack_detect(codec, 0x28);
-
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x31, &parm);
-	if (present) {
-		update_power_state(codec, 0x1c, AC_PWRST_D3);
-		update_power_state(codec, 0x3c, AC_PWRST_D3);
-		update_power_state(codec, 0x3e, AC_PWRST_D3);
-	} else {
-		update_power_state(codec, 0x1c, AC_PWRST_D0);
-		update_power_state(codec, 0x3c, AC_PWRST_D0);
-		update_power_state(codec, 0x3e, AC_PWRST_D0);
-	}
-
-	/* PW15 (33h), MW15 (1dh), MUX15(3dh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x33, &parm);
-	update_power_state(codec, 0x1d, parm);
-	update_power_state(codec, 0x3d, parm);
-
-}
-
 /* patch for vt1812 */
 static int patch_vt1812(struct hda_codec *codec)
 {
@@ -1656,8 +1163,6 @@
 	spec->init_verbs[spec->num_iverbs++]  = vt1812_init_verbs;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
 	return 0;
 }
 
@@ -1673,84 +1178,6 @@
 	{ }
 };
 
-static void set_widgets_power_state_vt3476(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm, parm2;
-	/* MUX10 (1eh) = stereo mixer */
-	imux_is_smixer =
-	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 4;
-	/* inputs */
-	/* PW 5/6/7 (29h/2ah/2bh) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x29, &parm);
-	set_pin_power_state(codec, 0x2a, &parm);
-	set_pin_power_state(codec, 0x2b, &parm);
-	if (imux_is_smixer)
-		parm = AC_PWRST_D0;
-	/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-	update_power_state(codec, 0x1e, parm);
-	update_power_state(codec, 0x1f, parm);
-	update_power_state(codec, 0x10, parm);
-	update_power_state(codec, 0x11, parm);
-
-	/* outputs */
-	/* PW3 (27h), MW3(37h), AOW3 (bh) */
-	if (spec->codec_type == VT1705CF) {
-		parm = AC_PWRST_D3;
-		update_power_state(codec, 0x27, parm);
-		update_power_state(codec, 0x37, parm);
-	}	else {
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x27, &parm);
-		update_power_state(codec, 0x37, parm);
-	}
-
-	/* PW2 (26h), MW2(36h), AOW2 (ah) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x26, &parm);
-	update_power_state(codec, 0x36, parm);
-	if (smart51_enabled(codec)) {
-		/* PW7(2bh), MW7(3bh), MUX7(1Bh) */
-		set_pin_power_state(codec, 0x2b, &parm);
-		update_power_state(codec, 0x3b, parm);
-		update_power_state(codec, 0x1b, parm);
-	}
-	update_conv_power_state(codec, 0xa, parm, 2);
-
-	/* PW1 (25h), MW1(35h), AOW1 (9h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x25, &parm);
-	update_power_state(codec, 0x35, parm);
-	if (smart51_enabled(codec)) {
-		/* PW6(2ah), MW6(3ah), MUX6(1ah) */
-		set_pin_power_state(codec, 0x2a, &parm);
-		update_power_state(codec, 0x3a, parm);
-		update_power_state(codec, 0x1a, parm);
-	}
-	update_conv_power_state(codec, 0x9, parm, 1);
-
-	/* PW4 (28h), MW4 (38h), MUX4(18h), AOW3(bh)/AOW0(8h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x28, &parm);
-	update_power_state(codec, 0x38, parm);
-	update_power_state(codec, 0x18, parm);
-	if (spec->gen.indep_hp_enabled)
-		update_conv_power_state(codec, 0xb, parm, 3);
-	parm2 = parm; /* for pin 0x0b */
-
-	/* PW0 (24h), MW0(34h), MW9(3fh), AOW0 (8h) */
-	parm = AC_PWRST_D3;
-	set_pin_power_state(codec, 0x24, &parm);
-	update_power_state(codec, 0x34, parm);
-	if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3)
-		parm = parm2;
-	update_conv_power_state(codec, 0x8, parm, 0);
-	/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-	update_power_state(codec, 0x3f, imux_is_smixer ? AC_PWRST_D0 : parm);
-}
-
 static int patch_vt3476(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -1774,9 +1201,6 @@
 	spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs;
 
 	codec->patch_ops = via_patch_ops;
-
-	spec->set_widgets_power_state = set_widgets_power_state_vt3476;
-
 	return 0;
 }
 
@@ -1884,23 +1308,11 @@
 
 MODULE_ALIAS("snd-hda-codec-id:1106*");
 
-static struct hda_codec_preset_list via_list = {
+static struct hda_codec_driver via_driver = {
 	.preset = snd_hda_preset_via,
-	.owner = THIS_MODULE,
 };
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("VIA HD-audio codec");
 
-static int __init patch_via_init(void)
-{
-	return snd_hda_add_codec_preset(&via_list);
-}
-
-static void __exit patch_via_exit(void)
-{
-	snd_hda_delete_codec_preset(&via_list);
-}
-
-module_init(patch_via_init)
-module_exit(patch_via_exit)
+module_hda_codec_driver(via_driver);
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
index 6ba0b55..0a4ad5f 100644
--- a/sound/pci/hda/thinkpad_helper.c
+++ b/sound/pci/hda/thinkpad_helper.c
@@ -21,7 +21,7 @@
 static bool is_thinkpad(struct hda_codec *codec)
 {
 	bool found = false;
-	if (codec->subsystem_id >> 16 != 0x17aa)
+	if (codec->core.subsystem_id >> 16 != 0x17aa)
 		return false;
 	if (ACPI_SUCCESS(acpi_get_devices("LEN0068", acpi_check_cb, &found, NULL)) && found)
 		return true;
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
index bcf30a3..9906119 100644
--- a/sound/pci/ice1712/wtm.c
+++ b/sound/pci/ice1712/wtm.c
@@ -29,12 +29,19 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <sound/core.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
 
 #include "ice1712.h"
 #include "envy24ht.h"
 #include "wtm.h"
 #include "stac946x.h"
 
+struct wtm_spec {
+	/* rate change needs atomic mute/unmute of all dacs*/
+	struct mutex mute_mutex;
+};
+
 
 /*
  *	2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
@@ -68,15 +75,65 @@
 /*
  *	DAC mute control
  */
+static void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute,
+				unsigned short int *change_mask)
+{
+	unsigned char new, old;
+	int id, idx, change;
+
+	/*stac9460 1*/
+	for (id = 0; id < 7; id++) {
+		if (*change_mask & (0x01 << id)) {
+			if (id == 0)
+				idx = STAC946X_MASTER_VOLUME;
+			else
+				idx = STAC946X_LF_VOLUME - 1 + id;
+			old = stac9460_get(ice, idx);
+			new = (~mute << 7 & 0x80) | (old & ~0x80);
+			change = (new != old);
+			if (change) {
+				stac9460_put(ice, idx, new);
+				*change_mask = *change_mask | (0x01 << id);
+			} else {
+				*change_mask = *change_mask & ~(0x01 << id);
+			}
+		}
+	}
+
+	/*stac9460 2*/
+	for (id = 0; id < 3; id++) {
+		if (*change_mask & (0x01 << (id + 7))) {
+			if (id == 0)
+				idx = STAC946X_MASTER_VOLUME;
+			else
+				idx = STAC946X_LF_VOLUME - 1 + id;
+			old = stac9460_2_get(ice, idx);
+			new = (~mute << 7 & 0x80) | (old & ~0x80);
+			change = (new != old);
+			if (change) {
+				stac9460_2_put(ice, idx, new);
+				*change_mask = *change_mask | (0x01 << id);
+			} else {
+				*change_mask = *change_mask & ~(0x01 << id);
+			}
+		}
+	}
+}
+
+
+
 #define stac9460_dac_mute_info		snd_ctl_boolean_mono_info
 
 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	struct wtm_spec *spec = ice->spec;
 	unsigned char val;
 	int idx, id;
 
+	mutex_lock(&spec->mute_mutex);
+
 	if (kcontrol->private_value) {
 		idx = STAC946X_MASTER_VOLUME;
 		id = 0;
@@ -89,6 +146,8 @@
 	else
 		val = stac9460_2_get(ice, idx - 6);
 	ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
+
+	mutex_unlock(&spec->mute_mutex);
 	return 0;
 }
 
@@ -338,8 +397,14 @@
 /*
  * MIC / LINE switch fonction
  */
+static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	static const char * const texts[2] = { "Line In", "Mic" };
 
-#define stac9460_mic_sw_info		snd_ctl_boolean_mono_info
+	return snd_ctl_enum_info(uinfo, 1, 2, texts);
+}
+
 
 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
@@ -353,7 +418,7 @@
 		val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 	else
 		val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-	ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
+	ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1;
 	return 0;
 }
 
@@ -369,7 +434,7 @@
 		old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
 	else
 		old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-	new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
+	new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80);
 	change = (new != old);
 	if (change) {
 		if (id == 0)
@@ -380,17 +445,63 @@
 	return change;
 }
 
+
+/*
+ * Handler for setting correct codec rate - called when rate change is detected
+ */
+static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
+{
+	unsigned char old, new;
+	unsigned short int changed;
+	struct wtm_spec *spec = ice->spec;
+
+	if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
+		return;
+	else if (rate <= 48000)
+		new = 0x08;     /* 256x, base rate mode */
+	else if (rate <= 96000)
+		new = 0x11;     /* 256x, mid rate mode */
+	else
+		new = 0x12;     /* 128x, high rate mode */
+
+	old = stac9460_get(ice, STAC946X_MASTER_CLOCKING);
+	if (old == new)
+		return;
+	/* change detected, setting master clock, muting first */
+	/* due to possible conflicts with mute controls - mutexing */
+	mutex_lock(&spec->mute_mutex);
+	/* we have to remember current mute status for each DAC */
+	changed = 0xFFFF;
+	stac9460_dac_mute_all(ice, 0, &changed);
+	/*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+	stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
+	stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new);
+	udelay(10);
+	/* unmuting - only originally unmuted dacs -
+	* i.e. those changed when muting */
+	stac9460_dac_mute_all(ice, 1, &changed);
+	mutex_unlock(&spec->mute_mutex);
+}
+
+
+/*Limits value in dB for fader*/
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
+
 /*
  * Control tabs
  */
 static struct snd_kcontrol_new stac9640_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			    SNDRV_CTL_ELEM_ACCESS_TLV_READ),
 		.name = "Master Playback Switch",
 		.info = stac9460_dac_mute_info,
 		.get = stac9460_dac_mute_get,
 		.put = stac9460_dac_mute_put,
-		.private_value = 1
+		.private_value = 1,
+		.tlv = { .p = db_scale_dac }
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -402,7 +513,7 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "MIC/Line switch",
+		.name = "MIC/Line Input Enum",
 		.count = 2,
 		.info = stac9460_mic_sw_info,
 		.get = stac9460_mic_sw_get,
@@ -419,11 +530,15 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			    SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+
 		.name = "DAC Volume",
 		.count = 8,
 		.info = stac9460_dac_vol_info,
 		.get = stac9460_dac_vol_get,
 		.put = stac9460_dac_vol_put,
+		.tlv = { .p = db_scale_dac }
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -435,12 +550,15 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			    SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+
 		.name = "ADC Volume",
 		.count = 2,
 		.info = stac9460_adc_vol_info,
 		.get = stac9460_adc_vol_get,
 		.put = stac9460_adc_vol_put,
-
+		.tlv = { .p = db_scale_adc }
 	}
 };
 
@@ -463,41 +581,53 @@
 
 static int wtm_init(struct snd_ice1712 *ice)
 {
-	static unsigned short stac_inits_prodigy[] = {
+	static unsigned short stac_inits_wtm[] = {
 		STAC946X_RESET, 0,
+		STAC946X_MASTER_CLOCKING, 0x11,
 		(unsigned short)-1
 	};
 	unsigned short *p;
+	struct wtm_spec *spec;
 
 	/*WTM 192M*/
 	ice->num_total_dacs = 8;
 	ice->num_total_adcs = 4;
 	ice->force_rdma1 = 1;
 
+	/*init mutex for dac mute conflict*/
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	ice->spec = spec;
+	mutex_init(&spec->mute_mutex);
+
+
 	/*initialize codec*/
-	p = stac_inits_prodigy;
+	p = stac_inits_wtm;
 	for (; *p != (unsigned short)-1; p += 2) {
 		stac9460_put(ice, p[0], p[1]);
 		stac9460_2_put(ice, p[0], p[1]);
 	}
+	ice->gpio.set_pro_rate = stac9460_set_rate_val;
 	return 0;
 }
 
 
 static unsigned char wtm_eeprom[] = {
-	0x47,	/*SYSCONF: clock 192KHz, 4ADC, 8DAC */
-	0x80,	/* ACLINK : I2S */
-	0xf8,	/* I2S: vol; 96k, 24bit, 192k */
-	0xc1	/*SPDIF: out-en, spidf ext out*/,
-	0x9f,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x7f,	/* GPIO_DIR2 */
-	0x9f,	/* GPIO_MASK */
-	0xff,	/* GPIO_MASK1 */
-	0x7f,	/* GPIO_MASK2 */
-	0x16,	/* GPIO_STATE */
-	0x80,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
+	[ICE_EEP2_SYSCONF]      = 0x67, /*SYSCONF: clock 192KHz, mpu401,
+							4ADC, 8DAC */
+	[ICE_EEP2_ACLINK]       = 0x80, /* ACLINK : I2S */
+	[ICE_EEP2_I2S]          = 0xf8, /* I2S: vol; 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]        = 0xc1, /*SPDIF: out-en, spidf ext out*/
+	[ICE_EEP2_GPIO_DIR]     = 0x9f,
+	[ICE_EEP2_GPIO_DIR1]    = 0xff,
+	[ICE_EEP2_GPIO_DIR2]    = 0x7f,
+	[ICE_EEP2_GPIO_MASK]    = 0x9f,
+	[ICE_EEP2_GPIO_MASK1]   = 0xff,
+	[ICE_EEP2_GPIO_MASK2]   = 0x7f,
+	[ICE_EEP2_GPIO_STATE]   = 0x16,
+	[ICE_EEP2_GPIO_STATE1]  = 0x80,
+	[ICE_EEP2_GPIO_STATE2]  = 0x00,
 };
 
 
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 2c5484e..749069a 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -1795,7 +1795,7 @@
 	},
 };
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
         {
 		.subvendor = 0x0e11,
 		.subdevice = 0x000e,
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index ca67f89..cb666c7 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6043,23 +6043,30 @@
 	.mask = 0
 };
 
-static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
+static int snd_hdspm_open(struct snd_pcm_substream *substream)
 {
 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	spin_lock_irq(&hdspm->lock);
-
 	snd_pcm_set_sync(substream);
+	runtime->hw = (playback) ? snd_hdspm_playback_subinfo :
+		snd_hdspm_capture_subinfo;
 
+	if (playback) {
+		if (hdspm->capture_substream == NULL)
+			hdspm_stop_audio(hdspm);
 
-	runtime->hw = snd_hdspm_playback_subinfo;
+		hdspm->playback_pid = current->pid;
+		hdspm->playback_substream = substream;
+	} else {
+		if (hdspm->playback_substream == NULL)
+			hdspm_stop_audio(hdspm);
 
-	if (hdspm->capture_substream == NULL)
-		hdspm_stop_audio(hdspm);
-
-	hdspm->playback_pid = current->pid;
-	hdspm->playback_substream = substream;
+		hdspm->capture_pid = current->pid;
+		hdspm->capture_substream = substream;
+	}
 
 	spin_unlock_irq(&hdspm->lock);
 
@@ -6094,108 +6101,42 @@
 				&hdspm_hw_constraints_aes32_sample_rates);
 	} else {
 		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-				snd_hdspm_hw_rule_rate_out_channels, hdspm,
+				(playback ?
+				 snd_hdspm_hw_rule_rate_out_channels :
+				 snd_hdspm_hw_rule_rate_in_channels), hdspm,
 				SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 	}
 
 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-			snd_hdspm_hw_rule_out_channels, hdspm,
+			(playback ? snd_hdspm_hw_rule_out_channels :
+			 snd_hdspm_hw_rule_in_channels), hdspm,
 			SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-			snd_hdspm_hw_rule_out_channels_rate, hdspm,
+			(playback ? snd_hdspm_hw_rule_out_channels_rate :
+			 snd_hdspm_hw_rule_in_channels_rate), hdspm,
 			SNDRV_PCM_HW_PARAM_RATE, -1);
 
 	return 0;
 }
 
-static int snd_hdspm_playback_release(struct snd_pcm_substream *substream)
+static int snd_hdspm_release(struct snd_pcm_substream *substream)
 {
 	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
+	bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	spin_lock_irq(&hdspm->lock);
 
-	hdspm->playback_pid = -1;
-	hdspm->playback_substream = NULL;
-
-	spin_unlock_irq(&hdspm->lock);
-
-	return 0;
-}
-
-
-static int snd_hdspm_capture_open(struct snd_pcm_substream *substream)
-{
-	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	spin_lock_irq(&hdspm->lock);
-	snd_pcm_set_sync(substream);
-	runtime->hw = snd_hdspm_capture_subinfo;
-
-	if (hdspm->playback_substream == NULL)
-		hdspm_stop_audio(hdspm);
-
-	hdspm->capture_pid = current->pid;
-	hdspm->capture_substream = substream;
-
-	spin_unlock_irq(&hdspm->lock);
-
-	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
-	snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
-
-	switch (hdspm->io_type) {
-	case AIO:
-	case RayDAT:
-		snd_pcm_hw_constraint_minmax(runtime,
-					     SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-					     32, 4096);
-		snd_pcm_hw_constraint_minmax(runtime,
-					     SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-					     16384, 16384);
-		break;
-
-	default:
-		snd_pcm_hw_constraint_minmax(runtime,
-					     SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-					     64, 8192);
-		snd_pcm_hw_constraint_minmax(runtime,
-					     SNDRV_PCM_HW_PARAM_PERIODS,
-					     2, 2);
-		break;
-	}
-
-	if (AES32 == hdspm->io_type) {
-		runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
-		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-				&hdspm_hw_constraints_aes32_sample_rates);
+	if (playback) {
+		hdspm->playback_pid = -1;
+		hdspm->playback_substream = NULL;
 	} else {
-		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-				snd_hdspm_hw_rule_rate_in_channels, hdspm,
-				SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+		hdspm->capture_pid = -1;
+		hdspm->capture_substream = NULL;
 	}
 
-	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-			snd_hdspm_hw_rule_in_channels, hdspm,
-			SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-
-	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-			snd_hdspm_hw_rule_in_channels_rate, hdspm,
-			SNDRV_PCM_HW_PARAM_RATE, -1);
-
-	return 0;
-}
-
-static int snd_hdspm_capture_release(struct snd_pcm_substream *substream)
-{
-	struct hdspm *hdspm = snd_pcm_substream_chip(substream);
-
-	spin_lock_irq(&hdspm->lock);
-
-	hdspm->capture_pid = -1;
-	hdspm->capture_substream = NULL;
-
 	spin_unlock_irq(&hdspm->lock);
+
 	return 0;
 }
 
@@ -6413,21 +6354,9 @@
 	return 0;
 }
 
-static struct snd_pcm_ops snd_hdspm_playback_ops = {
-	.open = snd_hdspm_playback_open,
-	.close = snd_hdspm_playback_release,
-	.ioctl = snd_hdspm_ioctl,
-	.hw_params = snd_hdspm_hw_params,
-	.hw_free = snd_hdspm_hw_free,
-	.prepare = snd_hdspm_prepare,
-	.trigger = snd_hdspm_trigger,
-	.pointer = snd_hdspm_hw_pointer,
-	.page = snd_pcm_sgbuf_ops_page,
-};
-
-static struct snd_pcm_ops snd_hdspm_capture_ops = {
-	.open = snd_hdspm_capture_open,
-	.close = snd_hdspm_capture_release,
+static struct snd_pcm_ops snd_hdspm_ops = {
+	.open = snd_hdspm_open,
+	.close = snd_hdspm_release,
 	.ioctl = snd_hdspm_ioctl,
 	.hw_params = snd_hdspm_hw_params,
 	.hw_free = snd_hdspm_hw_free,
@@ -6521,9 +6450,9 @@
 	strcpy(pcm->name, hdspm->card_name);
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-			&snd_hdspm_playback_ops);
+			&snd_hdspm_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-			&snd_hdspm_capture_ops);
+			&snd_hdspm_ops);
 
 	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
 
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 8622283..3dd038b 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1812,7 +1812,7 @@
 	chip->ac97 = NULL;
 }
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
 	{
 		.subvendor = 0x1106,
 		.subdevice = 0x4161,
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index dc9df00..337c317 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -192,6 +192,7 @@
 	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
 	{ USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
 	{ USB_ID(0x041e, 0x30df), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */
+	{ USB_ID(0x041e, 0x3237), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */
 	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 753a47d..7c5a701 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1113,24 +1113,37 @@
 
 bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
 {
-	/* MS Lifecam HD-5000 doesn't support reading the sample rate. */
-	return chip->usb_id == USB_ID(0x045E, 0x076D);
+	/* devices which do not support reading the sample rate. */
+	switch (chip->usb_id) {
+	case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema  */
+	case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */
+	case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
+		return true;
+	}
+	return false;
 }
 
 /* Marantz/Denon USB DACs need a vendor cmd to switch
  * between PCM and native DSD mode
  */
+static bool is_marantz_denon_dac(unsigned int id)
+{
+	switch (id) {
+	case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
+	case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
+	case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+		return true;
+	}
+	return false;
+}
+
 int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
 			      struct audioformat *fmt)
 {
 	struct usb_device *dev = subs->dev;
 	int err;
 
-	switch (subs->stream->chip->usb_id) {
-	case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
-	case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
-	case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
-
+	if (is_marantz_denon_dac(subs->stream->chip->usb_id)) {
 		/* First switch to alt set 0, otherwise the mode switch cmd
 		 * will not be accepted by the DAC
 		 */
@@ -1203,17 +1216,10 @@
 	/* Marantz/Denon devices with USB DAC functionality need a delay
 	 * after each class compliant request
 	 */
-	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) &&
-	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) {
-
-		switch (le16_to_cpu(dev->descriptor.idProduct)) {
-		case 0x1003: /* Denon DA300-USB */
-		case 0x3005: /* Marantz HD-DAC1 */
-		case 0x3006: /* Marantz SA-14S1 */
-			mdelay(20);
-			break;
-		}
-	}
+	if (is_marantz_denon_dac(USB_ID(le16_to_cpu(dev->descriptor.idVendor),
+					le16_to_cpu(dev->descriptor.idProduct)))
+	    && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+		mdelay(20);
 
 	/* Zoom R16/24 needs a tiny delay here, otherwise requests like
 	 * get/set frequency return as failed despite actually succeeding.
@@ -1268,15 +1274,9 @@
 	}
 
 	/* Denon/Marantz devices with USB DAC functionality */
-	switch (chip->usb_id) {
-	case USB_ID(0x154e, 0x1003): /* Denon DA300-USB */
-	case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
-	case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+	if (is_marantz_denon_dac(chip->usb_id)) {
 		if (fp->altsetting == 2)
 			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
-		break;
-	default:
-		break;
 	}
 
 	return 0;