ALSA: hda - Move a part of hda_codec stuff into hdac_device

Now some codes and functionalities of hda_codec struct are moved to
hdac_device struct.  A few basic attributes like the codec address,
vendor ID number, FG numbers, etc are moved to hdac_device, and they
are accessed like codec->core.addr.  The basic verb exec functions are
moved, too.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index 828680b..3c7625e 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,3 +1,3 @@
-snd-hda-core-objs := hda_bus_type.o hdac_bus.o
+snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o
 
 obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
new file mode 100644
index 0000000..a3f52ad
--- /dev/null
+++ b/sound/hda/hdac_device.c
@@ -0,0 +1,471 @@
+/*
+ * 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 "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_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)
+		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:
+	pm_runtime_put_noidle(&codec->dev);
+	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_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_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_bus_exec_verb(codec->bus, codec->addr, cmd, res);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_read);
+
+/**
+ * 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() directly.
+ */
+int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm)
+{
+	int val;
+
+	if (snd_hdac_read(codec, nid, AC_VERB_PARAMETERS, parm, &val))
+		return -1;
+	return val;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_read_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.
+ */
+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(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 - increment the runtime pm counter
+ * @codec: the codec object
+ */
+void snd_hdac_power_up(struct hdac_device *codec)
+{
+	struct device *dev = &codec->dev;
+
+	if (atomic_read(&codec->in_pm))
+		return;
+	pm_runtime_get_sync(dev);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_up);
+
+/**
+ * snd_hdac_power_up - decrement the runtime pm counter
+ * @codec: the codec object
+ */
+void snd_hdac_power_down(struct hdac_device *codec)
+{
+	struct device *dev = &codec->dev;
+
+	if (atomic_read(&codec->in_pm))
+		return;
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_down);
+#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/local.h b/sound/hda/local.h
new file mode 100644
index 0000000..a077d1f
--- /dev/null
+++ b/sound/hda/local.h
@@ -0,0 +1,19 @@
+/*
+ * 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;
+}
+
+#endif /* __HDAC_LOCAL_H */
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 4cdac3a..3364dc0 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -165,8 +165,8 @@
 	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);
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index 0b9ea70..ad276a9 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -14,36 +14,6 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 
-/* 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 */
-};
-
 /*
  * find a matching codec preset
  */
@@ -54,19 +24,19 @@
 		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->vendor_id;
+	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->afg)
+		if (preset->afg && preset->afg != codec->core.afg)
 			continue;
-		if (preset->mfg && preset->mfg != codec->mfg)
+		if (preset->mfg && preset->mfg != codec->core.mfg)
 			continue;
 		if (!mask)
 			mask = ~0;
 		if (preset->id == (id & mask) &&
-		    (!preset->rev || preset->rev == codec->revision_id)) {
+		    (!preset->rev || preset->rev == codec->core.revision_id)) {
 			codec->preset = preset;
 			return 1;
 		}
@@ -86,15 +56,11 @@
 /* reset the codec name from the preset */
 static int codec_refresh_name(struct hda_codec *codec, const char *name)
 {
-	char tmp[16];
-
-	kfree(codec->chip_name);
-	if (!name) {
-		sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
-		name = tmp;
+	if (name) {
+		kfree(codec->core.chip_name);
+		codec->core.chip_name = kstrdup(name, GFP_KERNEL);
 	}
-	codec->chip_name = kstrdup(name, GFP_KERNEL);
-	return codec->chip_name ? 0 : -ENOMEM;
+	return codec->core.chip_name ? 0 : -ENOMEM;
 }
 
 static int hda_codec_driver_probe(struct device *dev)
@@ -192,48 +158,23 @@
 static void codec_bind_module(struct hda_codec *codec)
 {
 #ifdef MODULE
-	request_module("snd-hda-codec-id:%08x", codec->vendor_id);
+	request_module("snd-hda-codec-id:%08x", codec->core.vendor_id);
 	if (codec_probed(codec))
 		return;
 	request_module("snd-hda-codec-id:%04x*",
-		       (codec->vendor_id >> 16) & 0xffff);
+		       (codec->core.vendor_id >> 16) & 0xffff);
 	if (codec_probed(codec))
 		return;
 #endif
 }
 
-/* store the codec vendor name */
-static int get_codec_vendor_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];
-
-	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;
-	return 0;
-}
-
 #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;
+	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);
 		switch (get_wcaps_type(wcaps)) {
 		case AC_WID_AUD_IN:
@@ -294,12 +235,6 @@
 {
 	int err;
 
-	if (!codec->vendor_name) {
-		err = get_codec_vendor_name(codec);
-		if (err < 0)
-			return err;
-	}
-
 	if (is_generic_config(codec))
 		codec->probe_id = HDA_CODEC_ID_GENERIC;
 	else
@@ -320,10 +255,10 @@
 	}
 
 	/* audio codec should override the mixer name */
-	if (codec->afg || !*codec->card->mixername)
+	if (codec->core.afg || !*codec->card->mixername)
 		snprintf(codec->card->mixername,
-			 sizeof(codec->card->mixername),
-			 "%s %s", codec->vendor_name, codec->chip_name);
+			 sizeof(codec->card->mixername), "%s %s",
+			 codec->core.vendor_name, codec->core.chip_name);
 	return 0;
 
  error:
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index f96bff3..ddfc0fb 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -40,7 +40,7 @@
 #include <sound/hda_hwdep.h>
 
 #ifdef CONFIG_PM
-#define codec_in_pm(codec)	atomic_read(&(codec)->in_pm)
+#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
@@ -48,6 +48,11 @@
 #define hda_codec_is_power_on(codec)	1
 #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
@@ -119,30 +124,6 @@
 EXPORT_SYMBOL_GPL(snd_hda_get_jack_type);
 
 /*
- * Compose a 32bit command word to be sent to the HD-audio controller
- */
-static inline unsigned int
-make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
-	       unsigned int verb, unsigned int parm)
-{
-	unsigned int addr = codec->core.addr;
-	u32 val;
-
-	if ((addr & ~0xf) || (nid & ~0x7f) ||
-	    (verb & ~0xfff) || (parm & ~0xffff)) {
-		codec_err(codec, "hda-codec: out of range cmd %x:%x:%x:%x\n",
-			  addr, nid, verb, parm);
-		return ~0;
-	}
-
-	val = (u32)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,
@@ -194,7 +175,7 @@
 				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))
 		return -1;
@@ -217,7 +198,7 @@
 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 cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm);
 	return codec_exec_verb(codec, cmd, flags, NULL);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_write);
@@ -237,30 +218,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;
@@ -401,128 +358,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
@@ -738,35 +573,6 @@
 EXPORT_SYMBOL_GPL(snd_hda_bus_new);
 
 /*
- * 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
  */
 static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
@@ -774,13 +580,11 @@
 	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++)
+	nid = codec->core.start_nid;
+	for (i = 0; i < codec->core.num_nodes; i++, nid++)
 		codec->wcaps[i] = snd_hda_param_read(codec, nid,
 						     AC_PAR_AUDIO_WIDGET_CAP);
 	return 0;
@@ -789,10 +593,9 @@
 /* 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);
@@ -1136,9 +939,6 @@
 	remove_conn_list(codec);
 }
 
-static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
-				hda_nid_t fg, unsigned int power_state);
-
 static unsigned int hda_set_power_state(struct hda_codec *codec,
 				unsigned int power_state);
 
@@ -1178,12 +978,10 @@
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 
 	free_init_pincfgs(codec);
-	snd_hdac_bus_remove_device(&codec->bus->core, &codec->core);
+	snd_hdac_device_exit(&codec->core);
 	snd_hda_sysfs_clear(codec);
 	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);
 	kfree(codec);
@@ -1201,7 +999,6 @@
 		      unsigned int codec_addr, struct hda_codec **codecp)
 {
 	struct hda_codec *codec;
-	struct device *dev;
 	char component[31];
 	hda_nid_t fg;
 	int err;
@@ -1220,19 +1017,16 @@
 	if (!codec)
 		return -ENOMEM;
 
-	codec->core.bus = &bus->core;
-	codec->core.addr = codec_addr;
-	codec->core.type = HDA_DEV_LEGACY;
+	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;
+	}
 
-	dev = hda_codec_dev(codec);
-	device_initialize(dev);
-	dev->parent = bus->core.dev;
-	dev->bus = &snd_hda_bus_type;
-	dev->release = snd_hda_codec_dev_release;
-	dev->groups = snd_hda_dev_attr_groups;
-	dev_set_name(dev, "hdaudioC%dD%d", card->number, codec_addr);
-	dev_set_drvdata(dev, codec); /* for sysfs */
-	device_enable_async_suspend(dev);
+	codec->core.dev.release = snd_hda_codec_dev_release;
+	codec->core.type = HDA_DEV_LEGACY;
 
 	codec->bus = bus;
 	codec->card = card;
@@ -1258,12 +1052,6 @@
 	codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
 
 #ifdef CONFIG_PM
-	/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
-	 * it's powered down later in snd_hda_codec_dev_register().
-	 */
-	set_bit(codec->core.addr, &bus->core.codec_powered);
-	pm_runtime_set_active(hda_codec_dev(codec));
-	pm_runtime_get_noresume(hda_codec_dev(codec));
 	codec->power_jiffies = jiffies;
 #endif
 
@@ -1277,31 +1065,7 @@
 		}
 	}
 
-	err = snd_hdac_bus_add_device(&bus->core, &codec->core);
-	if (err < 0)
-		goto error;
-
-	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) {
-		codec_err(codec, "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)
 		goto error;
@@ -1309,19 +1073,6 @@
 	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);
-
 	/* power-up all before initialization */
 	hda_set_power_state(codec, AC_PWRST_D0);
 
@@ -1329,8 +1080,8 @@
 
 	snd_hda_create_hwdep(codec);
 
-	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
-		codec->subsystem_id, codec->revision_id);
+	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(card, SNDRV_DEV_CODEC, codec, &dev_ops);
@@ -1342,6 +1093,7 @@
 	return 0;
 
  error:
+	pm_runtime_put_noidle(hda_codec_dev(codec));
 	put_device(hda_codec_dev(codec));
 	return err;
 }
@@ -1359,11 +1111,15 @@
 	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)
 		return err;
@@ -1663,7 +1419,7 @@
 				 int direction)
 {
 	if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
-		nid = codec->afg;
+		nid = codec->core.afg;
 	return snd_hda_param_read(codec, nid,
 				  direction == HDA_OUTPUT ?
 				  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
@@ -3664,10 +3420,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))
@@ -3684,22 +3439,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,
@@ -3738,7 +3477,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 &&
@@ -3758,7 +3497,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;
@@ -3766,7 +3505,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;
@@ -3800,14 +3539,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))
@@ -3858,14 +3596,14 @@
 {
 	unsigned int state;
 
-	atomic_inc(&codec->in_pm);
+	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);
 	update_power_acct(codec, true);
-	atomic_dec(&codec->in_pm);
+	atomic_dec(&codec->core.in_pm);
 	return state;
 }
 
@@ -3890,7 +3628,7 @@
  */
 static void hda_call_codec_resume(struct hda_codec *codec)
 {
-	atomic_inc(&codec->in_pm);
+	atomic_inc(&codec->core.in_pm);
 
 	hda_mark_cmd_cache_dirty(codec);
 
@@ -3913,7 +3651,7 @@
 		hda_jackpoll_work(&codec->jackpoll_work.work);
 	else
 		snd_hda_jack_report_sync(codec);
-	atomic_dec(&codec->in_pm);
+	atomic_dec(&codec->core.in_pm);
 }
 
 static int hda_codec_runtime_suspend(struct device *dev)
@@ -3926,8 +3664,9 @@
 	list_for_each_entry(pcm, &codec->pcm_list_head, list)
 		snd_pcm_suspend_all(pcm->pcm);
 	state = hda_call_codec_suspend(codec);
-	if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK))
-		clear_bit(codec->core.addr, &codec->bus->core.codec_powered);
+	if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
+	    (state & AC_PWRST_CLK_STOP_OK))
+		snd_hdac_codec_link_down(&codec->core);
 	return 0;
 }
 
@@ -3935,7 +3674,7 @@
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 
-	set_bit(codec->core.addr, &codec->bus->core.codec_powered);
+	snd_hdac_codec_link_up(&codec->core);
 	hda_call_codec_resume(codec);
 	pm_runtime_mark_last_busy(dev);
 	return 0;
@@ -4129,11 +3868,11 @@
 				  int dir)
 {
 	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;
@@ -4150,7 +3889,7 @@
 {
 	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;
@@ -4632,39 +4371,6 @@
 EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
 
 #ifdef CONFIG_PM
-/**
- * snd_hda_power_up - Power-up the codec
- * @codec: HD-audio codec
- *
- * Increment the usage counter and resume the device if not done yet.
- */
-void snd_hda_power_up(struct hda_codec *codec)
-{
-	struct device *dev = hda_codec_dev(codec);
-
-	if (codec_in_pm(codec))
-		return;
-	pm_runtime_get_sync(dev);
-}
-EXPORT_SYMBOL_GPL(snd_hda_power_up);
-
-/**
- * snd_hda_power_down - Power-down the codec
- * @codec: HD-audio codec
- *
- * Decrement the usage counter and schedules the autosuspend if none used.
- */
-void snd_hda_power_down(struct hda_codec *codec)
-{
-	struct device *dev = hda_codec_dev(codec);
-
-	if (codec_in_pm(codec))
-		return;
-	pm_runtime_mark_last_busy(dev);
-	pm_runtime_put_autosuspend(dev);
-}
-EXPORT_SYMBOL_GPL(snd_hda_power_down);
-
 static void codec_set_power_save(struct hda_codec *codec, int delay)
 {
 	struct device *dev = hda_codec_dev(codec);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 6efcb4a..e7c47a4 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -261,24 +261,10 @@
 	struct hda_bus *bus;
 	struct snd_card *card;
 	unsigned int addr;	/* codec addr*/
-
-	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;
-	const char *vendor_name;	/* codec vendor name */
-	const char *chip_name;		/* codec chip name */
 	const char *modelname;	/* model name for preset */
 
 	/* set by patch */
@@ -295,8 +281,6 @@
 	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 */
@@ -347,14 +331,11 @@
 	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 d3_stop_clk:1;	/* support D3 operation without BCLK */
-	atomic_t in_pm;		/* suspend/resume being performed */
 	unsigned long power_on_acct;
 	unsigned long power_off_acct;
 	unsigned long power_jiffies;
@@ -395,11 +376,6 @@
 #define list_for_each_codec(c, bus) \
 	list_for_each_entry(c, &(bus)->core.codec_list, core.list)
 
-/* direction */
-enum {
-	HDA_INPUT, HDA_OUTPUT
-};
-
 /* snd_hda_codec_read/write optional flags */
 #define HDA_RW_NO_RESPONSE_FALLBACK	(1 << 0)
 
@@ -422,8 +398,8 @@
 			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);
+#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
@@ -431,9 +407,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,
@@ -582,14 +561,12 @@
 /*
  * power saving
  */
+#define snd_hda_power_up(codec)		snd_hdac_power_up(&(codec)->core)
+#define snd_hda_power_down(codec)	snd_hdac_power_down(&(codec)->core)
 #ifdef CONFIG_PM
-void snd_hda_power_up(struct hda_codec *codec);
-void snd_hda_power_down(struct hda_codec *codec);
 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_up(struct hda_codec *codec) {}
-static inline void snd_hda_power_down(struct hda_codec *codec) {}
 static inline void snd_hda_set_power_save(struct hda_bus *bus, int delay) {}
 #endif
 
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 0ef2459..4850f92 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -654,7 +654,7 @@
 	int type = get_wcaps_type(get_wcaps(codec, nid));
 	int i, n;
 
-	if (nid == codec->afg)
+	if (nid == codec->core.afg)
 		return true;
 
 	for (n = 0; n < spec->paths.used; n++) {
@@ -832,7 +832,7 @@
 
 	for (i = 0; i < path->depth; i++) {
 		nid = path->path[i];
-		if (nid == codec->afg)
+		if (nid == codec->core.afg)
 			continue;
 		if (!allow_powerdown || is_active_nid_for_any(codec, nid))
 			state = AC_PWRST_D0;
@@ -1897,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)) {
@@ -3067,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);
 
@@ -3864,8 +3862,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;
@@ -4706,7 +4703,7 @@
 						  hda_nid_t nid,
 						  unsigned int power_state)
 {
-	if (power_state != AC_PWRST_D0 || nid == codec->afg)
+	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;
@@ -5478,7 +5475,7 @@
 
 	fill_pcm_stream_name(spec->stream_name_analog,
 			     sizeof(spec->stream_name_analog),
-			     " Analog", codec->chip_name);
+			     " Analog", codec->core.chip_name);
 	info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
 	if (!info)
 		return -ENOMEM;
@@ -5509,7 +5506,7 @@
 	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);
+				     " Digital", codec->core.chip_name);
 		info = snd_hda_codec_pcm_new(codec, "%s",
 					     spec->stream_name_digital);
 		if (!info)
@@ -5544,7 +5541,7 @@
 	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);
+			     " Alt Analog", codec->core.chip_name);
 		info = snd_hda_codec_pcm_new(codec, "%s",
 					     spec->stream_name_alt_analog);
 		if (!info)
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 1d00164..e0db30c 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -515,15 +515,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 */
@@ -547,9 +550,9 @@
 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);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index dacfe74..a4f5a30 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -289,7 +289,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)
@@ -597,7 +597,7 @@
 		       struct hda_codec *codec, hda_nid_t nid)
 {
 	unsigned int gpio =
-		snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+		snd_hda_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 +667,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,29 +691,39 @@
 		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 =
@@ -860,7 +866,7 @@
 	struct snd_info_entry *entry;
 	int err;
 
-	snprintf(name, sizeof(name), "codec#%d", codec->addr);
+	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 3b5ed11..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,
@@ -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,			\
@@ -553,9 +553,9 @@
 	*codecp = NULL;
 	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
 		list_for_each_codec(codec, bus) {
-			if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
-			    (subid <= 0 || codec->subsystem_id == subid) &&
-			    codec->addr == caddr) {
+			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/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 af4c7be..2278e83 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:
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 72d2065..5aff35a 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -4243,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);
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 142a6cf..1e21f9f 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))
@@ -848,7 +846,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 +860,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 +894,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;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 7e9ff7b..35d92a8 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 {
@@ -1391,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);
 
@@ -1728,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;
@@ -2928,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 */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 124eacf..eee4532 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
@@ -826,9 +826,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 +904,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 +913,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 +1785,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 +1793,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 +2269,7 @@
 
 	spec = codec->spec;
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0882:
 	case 0x10ec0885:
 	case 0x10ec0900:
@@ -3067,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)
@@ -3112,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)
@@ -3479,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;
@@ -3564,7 +3564,7 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
 		alc_process_coef_fw(codec, coef0255);
 		break;
@@ -3619,7 +3619,7 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
 		alc_write_coef_idx(codec, 0x45, 0xc489);
 		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
@@ -3688,7 +3688,7 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
 		alc_process_coef_fw(codec, coef0255);
 		break;
@@ -3742,7 +3742,7 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
 		alc_process_coef_fw(codec, coef0255);
 		break;
@@ -3796,7 +3796,7 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
 		alc_process_coef_fw(codec, coef0255);
 		break;
@@ -3841,7 +3841,7 @@
 		{}
 	};
 
-	switch (codec->vendor_id) {
+	switch (codec->core.vendor_id) {
 	case 0x10ec0255:
 		alc_process_coef_fw(codec, coef0255);
 		msleep(300);
@@ -4078,7 +4078,7 @@
 
 	/* 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;
 }
@@ -5428,7 +5428,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) {
@@ -5772,9 +5772,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;
@@ -5819,7 +5819,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;
 }
@@ -6317,7 +6317,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;
@@ -6347,7 +6347,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;
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index df24313..49b4868 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -205,8 +205,8 @@
 		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,7 +223,7 @@
 	u16 val;
 
 	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);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 5b7c173..b314551 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;
@@ -2134,7 +2136,7 @@
 		spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
 #ifdef CONFIG_PM
 		/* resetting controller clears GPIO, so we need to keep on */
-		codec->d3_stop_clk = 0;
+		codec->core.power_caps &= ~AC_PWRST_CLKSTOP;
 #endif
 	}
 }
@@ -3031,9 +3033,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;
@@ -3093,7 +3095,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  ||
@@ -3792,7 +3794,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;
@@ -4053,9 +4055,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;
@@ -4302,7 +4304,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);
 
@@ -4338,7 +4340,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));
@@ -4349,7 +4351,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 */
@@ -4357,21 +4359,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
@@ -4597,7 +4599,8 @@
 	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;
@@ -4647,7 +4650,8 @@
 	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;
@@ -4706,14 +4710,14 @@
 	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++;
 		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 */
@@ -4722,7 +4726,7 @@
 		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;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 485663b..a34d767 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -140,7 +140,7 @@
 
 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;
@@ -335,7 +335,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)
@@ -558,7 +558,7 @@
 	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
@@ -714,19 +714,19 @@
 
 	/* correct names for VT1708BCE */
 	if (get_codec_type(codec) == VT1708BCE)	{
-		kfree(codec->chip_name);
-		codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
+		kfree(codec->core.chip_name);
+		codec->core.chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
 		snprintf(codec->card->mixername,
 			 sizeof(codec->card->mixername),
-			 "%s %s", codec->vendor_name, codec->chip_name);
+			 "%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);
+	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->vendor_name, codec->chip_name);
+			 "%s %s", codec->core.vendor_name, codec->core.chip_name);
 	}
 
 	/* automatic parse from the BIOS config */
@@ -815,8 +815,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)) {
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;